루프는 모든 프로그래밍 언어에서 가장 중요한 메커니즘 중 하나이며, 실질적인 중요성 (분류, 쿼리 등)을 가진 거의 모든 컴퓨터 프로그램에서 루프가 열려 있지 않습니다. 루핑은 또한 프로그램 최적화의 매우 번거로운 부분입니다. 우리는 종종 프로그램의 복잡성을 지속적으로 최적화해야하지만, 루핑으로 인한 시간 복잡성과 공간 복잡성 사이의 선택에 얽혀 있습니다.
javaScript에는 () {}에 대한 3 개의 기본 루프가 있고 () {} 및 {}는 ()와 가장 일반적으로 사용되는 것은 () {}에 대한 것입니다.
그러나 프로그램을 최적화 할 때 JavaScript 엔지니어가 무시할 가능성이 가장 높은 루프입니다.
먼저 기본 지식을 검토합시다.
JavaScript의 구문은 C 언어에서 상속되며 For Loops의 기본 구문을 사용하는 두 가지 방법이 있습니다.
1. 루핑 어레이
루프의 기본 구문
코드 사본은 다음과 같습니다.
for ( / * 초기화 * /2 / * 판단 조건 * /2 / * 루프 처리 * /) {
// ... 논리 코드
}
인스턴스 코드로 자세히 설명하겠습니다.
코드 사본은 다음과 같습니다.
var array = [1, 2, 3, 4, 5];
var sum = 0;
for (var i = 0, len = array.length; i <len; ++ i) {
sum += 배열 [i];
}
Console.log ( '배열/'항목의 합은 %d. ', sum);
// => 배열 항목의 합은 15입니다.
이 코드에서는 먼저 축적 할 항목과 합계 변수를 저장하는 배열을 정의하고 초기화합니다. 다음으로, 우리는 루프를 시작합니다. 루프에 대한 이것의 초기화 코드에서, 우리는 또한 두 가지 변수의 I (카운터)와 len (루프 배열 길이의 별칭)을 정의하고 초기화합니다. LEN보다 적을 때 루프 조건이 설정되고 논리 코드가 실행됩니다. 각 논리 코드가 실행되면 1만큼 증가합니다.
루프의 논리 코드에서 현재 루프의 배열 항을 합계 변수에 추가합니다.
이주기는 다음과 같이 유량 차트로 표시됩니다.
이 흐름도에서 프로그램의 실제 루프 본문에는 논리 코드뿐만 아니라 루프 자체를 구현하는 실행 판단 및 루프 처리도 포함되어 있음을 찾기가 어렵지 않습니다.
이런 식으로, 우리의 최적화 아이디어는 명확하고 우리는 네 가지 측면에서 최적화 할 수 있습니다.
1. 루프 본체 이전의 초기화 코드
2. 루프 본체의 실행 판단 조건
3. 논리 코드
4. 논리 코드 후 코드 처리
추신 : 첫 번째 요점과 두 번째 요점 사이에는 중요한 관계가 있습니다.
1.1 초기화 코드 및 실행 판단 조건을 최적화하십시오
먼저 모든 사람이 친숙한 코드를 살펴 보겠습니다.
코드 사본은 다음과 같습니다.
// 잘못된!
for (var i = 02 i <list.length2 ++ i) {
// ... 논리 코드
}
JavaScript를 작성하는 대부분의 엔지니어는 여전히이 겉보기에 정상적인 루프 방법을 사용하고 있다고 생각하지만 왜 여기에서 잘못되었다고 말하는 이유는 무엇입니까?
이 루프의 모든 것을 분해하고 살펴 보겠습니다.
1. 코드 초기화 -이 루프는 카운터 변수 만 정의하고 초기화합니다.
2. 실행 판단 조건 - 카운터가 목록의 길이보다 적을 때는 그렇습니다.
3. 처리 코드 - 카운터는 1 증가합니다.
위의 흐름도를 검토하고 문제가 있는지 알아 봅시다.
실제 루프 본문에는 논리 코드가있을뿐만 아니라 루프 자체를 구현하는 실행 판단 및 처리 코드도 포함됩니다. 다시 말해, 판단 조건 i <list.length는 각 루프 전에 실행해야합니다. JavaScript에서는 객체의 속성 또는 방법을 읽을 때 쿼리가 필요합니다.
당신은 무언가를 이해하는 것 같습니다. 이 판단 조건에는 두 가지 작업이 있습니다. 1. 목록 배열에서 길이 속성을 쿼리하십시오. 2. i와 list.length의 크기를 비교하십시오.
목록 배열에 n 요소가 포함된다고 가정하면 프로그램은이 루프의 실행 판단에서 2N 작업을 수행해야합니다.
코드를 이것으로 변경하면 다음과 같습니다.
코드 사본은 다음과 같습니다.
// 잘
for (var i = 0, len = list.length; i <len; ++ i) {
// ...
}
이 개선 된 코드에서는 정의를 추가하고 LEN 변수를 초기화하여 LOOP 본체 실행 전에 초기화 코드에 LEST.LENGTH의 값을 저장했습니다 (변수, 표현, 포인터 및 값에 대한 관련 내용은 두 번째 기사에서 설명합니다). 이런 식으로, 우리는 루프 본체의 실행 판단에서 목록 배열을 다시 쿼리 할 필요가 없으며, 오페라는 원본의 절반입니다.
위의 단계에서, 우리는 알고리즘의 시간 복잡성을 개선했으며, 공간 복잡성을 계속 최적화하려면 어떻게해야합니까? LOOP 순서로 논리 코드가 제한되지 않으면 다음 최적화 방법을 시도해 볼 수 있습니다.
코드 사본은 다음과 같습니다.
for (var i = list.length -1; i> = 0; --i) {
// ...
}
이 코드는 마지막 요소 첨자 (list.length -1)부터 시작하여 루프 순서를 반전시켜 전진합니다. 루프에 필요한 변수 수를 1로 줄이려면 실행 판단에서 변수 쿼리 수가 줄어들고 CPU 명령을 실행하기 전에 소비 된 시간이 줄어 듭니다.
1.2 논리 코드 최적화
루프에서, 우리는 루프의 현재 배열 요소를 가져 와서 자연스럽게 그것에 대해 약간의 작업을 수행하거나 사용하여 요소에 대한 여러 통화로 이어집니다.
코드 사본은 다음과 같습니다.
var array = [
{이름 : 'Will Wen Gunn', type : 'hentai'},
{이름 : 'Vill Lin', type : 'moegril'}}
];
for (var i = array.length -1; i> = 0; --i) {
Console.log ( '이름 : %s', 배열 [i] .name);
console.log ( '그/그녀는 (n) %s', 배열 [i] .type);
Console.log ( '/r/n');
}
/*=>
이름 : Vill Lin
그/그녀는 (n) 무어 릴입니다
이름 : Wen Gunn
그/그녀는 (n) 헨타이입니다
*/
이 코드에서 프로그램은 각 배열 요소의 이름 및 유형 속성을 쿼리해야합니다. 배열에 n 요소가있는 경우 프로그램은 4N 객체 쿼리를 수행합니다.
코드 사본은 다음과 같습니다.
1. 배열 [i]
2. 배열 [i]. 이름
3. 배열 [i]
4. 배열 [i]. 타입
현재 솔루션을 생각해야한다고 생각합니다. 즉, 현재 배열 요소의 값을 변수에 할당 한 다음 논리 코드에서 사용합니다.
코드 사본은 다음과 같습니다.
var array = [
{이름 : 'Will Wen Gunn', type : 'hentai'},
{이름 : 'Vill Lin', type : 'moegril'}}
];
var person = null;
for (var i = array.length -1; i> = 0 && (person = array [i]); --i) {
Console.log ( '이름 : %s', person.name);
console.log ( '그/그녀는 (n) %s', person.type);
Console.log ( '/r/n');
}
사람 = null;
이것은 훨씬 더 아름답게 보입니다.
코드 사본은 다음과 같습니다.
1. 배열 [i] => var person
2. 사람. 이름
3. person.type
EmcaScript5의 Foreach와 약간 비슷하지만이 둘의 차이는 거대하므로 여기서 설명하지 않을 것입니다.
추신 : 교정 해 주셔서 감사합니다. 실험 후, 배열의 요소가 값을 직접 전달하여 정의되면 루프에서 얻은 값은 포인터가 아닌 값이어야합니다. 따라서 표현식이나 변수를 정의하든 추가 메모리 공간 요청이 있습니다.
1.3 처리 코드를 최적화합니다
실제로, 루프 본문에서 처리 코드를 최적화 할 수는 없으며, I 카운터는 1 자체로 1을 증가시키기에 충분합니다.
추신 : 좋은 제안이나 방법이 있으면 제공하십시오. :)
2. 원형 물체 (물체)
JavaScript에서는 객체의 특성과 방법을 가로 질러 가질 수 있습니다. for 루프는 객체가 속한 랩핑 유형 또는 생성자의 프로토 타입 특성 및 방법을 통과 할 수 없다는 점에 유의해야합니다.
구문은 루핑 어레이보다 간단합니다.
코드 사본은 다음과 같습니다.
for (/* 개체의 초기화*/ var 키) {
// ... 논리 코드
}
우리는 종종이 방법을 사용하여 객체에서 작동합니다.
코드 사본은 다음과 같습니다.
var person = {
'이름': 'wen wen gunn',
'타입': '헨타이',
'기술': [ '프로그래밍', '사진', '말하기', '등']
};
for (직접 var 키) {
value = person [키];
// 값이 배열 인 경우 문자열로 변환합니다.
if (배열의 값 인스턴스) {
값 = value.join ( ',');
}
console.log ( ' %s : %s', 키, 값);
}
/*=>
이름 : Wen Gunn
유형 : 헨타이
기술 : 프로그래밍, 사진, 말하기 등
*/
MongoDB를 사용했다면 쿼리 메커니즘에 익숙 할 것입니다. MongoDB의 쿼리 메커니즘은 API의 영혼과 같기 때문에 Flexible Curd Operation 방법은 MongoDB에 많은 인기와 개발 모멘텀을 얻었습니다.
Mongo API의 NANODB 구현에서 쿼리 구현은 대규모로 루프 객체를 사용합니다.
코드 사본은 다음과 같습니다.
var mydb = nano.db ( 'mydb');
var mycoll = mydb.collection ( 'mycoll');
var _cursor = mycoll.find ({
유형 : 'Repo',
언어 : 'JavaScript'
});
_커서
.종류({
별 : 1
})
.toArray (함수 (err, 행) {
if (err)
return console.error (err);
Console.log (행);
});
우리가 최적화해야 할 것은 루프 자체가 아니라 통과 해야하는 객체의 최적화입니다.
예를 들어, NANODB의 NANOCOLLECTION 클래스는 모든 요소 또는 객체를 포함하는 배열처럼 보이며 요소의 ID를 키로 사용한 다음 요소를 저장합니다.
그러나 이것은 사실이 아닙니다. 밑줄을 사용한 학생들은 _.invert 방법을 알아야합니다. 이것은 전달되는 물체의 키와 값을 되돌리는 매우 흥미로운 방법입니다.
코드 사본은 다음과 같습니다.
var person = {
'이름': 'wen wen gunn',
'타입': '헨타이'
};
var _inverted = _.invert (사람);
Console.log (_inverted);
/*=>
{
'wen gunn': 'name',
'헨타이': '타입'
}
*/
루프 객체를 사용하여 객체의 특정 속성 값을 쿼리 해야하는 경우 다음 방법을 시도해 볼 수 있습니다.
코드 사본은 다음과 같습니다.
var person = {
'이름': 'wen wen gunn',
'타입': '헨타이'
};
var name = 'wen gunn';
var _inverted = _.invert (사람);
if (_inverted [name] === 'name') {
Console.log ( 'Catched!');
}
// => 캐치!
그러나 객체 쿼리에 사용하기위한 최적화는 많지 않으며 모든 것이 실제 요구를 기반으로해야합니다. : p
다음으로 우리는 다른 두 루프를보고 () {}를보고 {} while while ()를 살펴 봅니다. 컴퓨터 과학 과정을받은 친구는이 두주기에 익숙 할 것이라고 생각합니다. 그들 사이의 유일한 차이점은 루프 본체의 논리적 실행 순서입니다.
while () {}의 실행 순서는 () {}의 실행 순서와 유사합니다. 실행 판단은 논리 코드 전에 수행되지만 초기화 및 처리 코드는 생략됩니다.
조건이 주어지면 조건이 더 이상 유지되지 않을 때까지 논리 코드가 실행됩니다.
코드 사본은 다음과 같습니다.
var sum = 0;
while (sum <10) {
합 + = 합계 + 1;
}
Console.log (합);
// => 15
()은 논리 코드 후에 실행 판결을 내리는 동안 {}를 수행합니다. 이는 "먼저 죽은 다음 플레이"를 의미합니다.
코드 사본은 다음과 같습니다.
var sum = 0;
하다 {
합 + = 합계 + 1;
} while (sum <10);
Console.log (합);
// => 15
() {} 및 do {}는 ({}도 카운터가 필요하지 않지만 특정 조건을 사용하여 논리 코드를 실행할지 또는 계속 실행할지 여부를 결정하십시오.
3. while () {} 및 do {} whike whike ()
() {} 및 do {} 반면 ()는 주로 비즈니스 로직에 사용되며 작업 대기열과 같은 특정 목적을 달성하기 위해 일련의 작업이 지속적으로 실행됩니다.
그러나이 두 루프는 기본적으로 실행 조건에 의해서만 제어되기 때문에 위험합니다. 논리 코드에서 실행 판단에 영향을 미치지 않으면 죽은 루프가 발생합니다.
코드 사본은 다음과 같습니다.
var sum = 02
// 경고!
while (sum <10) {
합 = 1 + 12
}
이러한 코드는 while (true) {}와 다르지 않으므로 사용하기 전에 실행 조건과 실행 조건에 영향을 미치는 방법을 명확히해야합니다.
4. 루프 제어 문을 잘 활용하십시오
나는 모든 JavaScript 엔지니어가 Break 문을 사용했지만 계속 진술은 상대적으로 거의 사용되지 않는다고 생각합니다. 실제로, 찾을 수있는 우수한 JavaScript 오픈 소스 프로젝트가 많이 있습니다.
계속 명령문의 기능을 해결하려면 먼저 예제 코드를 살펴 보겠습니다.
코드 사본은 다음과 같습니다.
// node.js 방송 서버
var net = 요구 사항 ( 'net');
var util = 요구 ( 'util');
var broadcastserver = net.createserver ();
// 클라이언트 스토어
broadcastserver.clients = [];
// 클라이언트 방송 방법
net.socket.prototype.broadcast = function (msg) {
var clients = broadcastserver.clients;
// 중앙 집중식에서 브로드 캐스트 클라이언트 첨자를받습니다.
var index = clients.indexof (this);
for (var i = clients.length -1; i> = 0; --i) {
if (i === index) {
// 방송 클라이언트 인 경우 현재 루프 본체가 종료됩니다.
계속하다;
}
currclient = 클라이언트 [i];
if (! currclient.destroyed) {
currclient.write (
util.format (
'/r [echo client %s : %d] %s/ninput :',
Currclient.remoteaddress, currclient.remoteport, msg)
);
}
}
};
// 새로운 클라이언트가 연결되어 있습니다
broadcastserver.on ( 'Connection', function (client) {
broadcastserver.clients.push (클라이언트);
// 환영
client.write ( '[Broadcast Server] 환영!/ninput :');
client.broadcast (Client, 'Joined!');
// 메시지 핸들
client.on ( 'data', function (msg) {
client.broadcast (msg);
client.write ( '/rinput :');
});
// 핸들을 분리합니다
client.on ( 'end', function () {
client.broadcast ( '왼쪽!');
})
});
// 바인딩
broadcastserver.listen (8080, function () {
Console.log ( '방송 서버 바운드');
});
이 코드는 Node.js Net 모듈을 기반으로 브로드 캐스트 서버를 구현합니다. 방송 방법에서는 계속 명세서를 사용하여 방송 클라이언트를 제외한 연결을 설정 한 모든 연결된 클라이언트를 구현합니다.
코드 컨텐츠는 매우 간단합니다. 클라이언트가 다른 클라이언트로 방송 해야하는 경우 해당 클라이언트 객체의 브로드 캐스트 방법을 클라이언트로 호출합니다. 브로드 캐스트 방법 에서이 프로그램은 먼저 캐시 된 클라이언트 소켓 컬렉션에서 현재 클라이언트의 위치 위시를 얻은 다음 모든 클라이언트 소켓을 통해 루프합니다. 루프 카운터가 이전에 얻은 위치 위시에 도달하면 현재 루프 본체의 논리 코드가 건너 뜁니다. 다음 루프가 계속됩니다.
C/C ++ 언어를 배운 엔지니어는 "Goto 진술을 사용하지 마십시오"라는 다양한 장소 에서이 조언을받을 것이라고 생각합니다.
이 "악명 높은"GOTO 문은 실제로 코드 흐름 컨트롤러이며, GOTO 문의 세부 사항은 여기에서 자세히 설명되지 않습니다. 그러나 JavaScript에는 명백한 GOTO 진술이 없지만 Break 문과 계속 문서에서 JavaScript에서 Goto의 그림자를 찾는 것은 어렵지 않습니다.
이는 중단 명세서 및 계속 명세서가 코드 리디렉션에 대한 정의 된 레이블 이름을 수락 할 수 있기 때문입니다.
MDN에서 제공 한 예제 코드를 살펴 보겠습니다.
코드 사본은 다음과 같습니다.
var i, j;
루프 1 :
for (i = 0; i <3; i ++) {// 문의 첫 번째는 "loop1"으로 표시됩니다.
루프 2 :
for (j = 0; j <3; j ++) {// 문의 두 번째는 "loop2"로 표시됩니다.
if (i == 1 && j == 1) {
계속 LOOP1;
} 또 다른 {
console.log ( "i =" + i + ", j =" + j);
}
}
}
// 출력은 다음과 같습니다.
// "i = 0, j = 0"
// "i = 0, j = 1"
// "i = 0, j = 2"
// "i = 1, j = 0"
// "i = 2, j = 0"
// "i = 2, j = 1"
// "i = 2, j = 2"
// "i = 1, j = 1"및 "i = 1, j = 2"를 모두 건너 뛰는 방법에 주목하십시오.
이 예제 코드에서는 2 층 루프가 구현되고 레이블이 각 루프 외부로 정의되며, 이는 후속 계속 명령문을 호출하는 데 사용됩니다.
루프의 첫 번째 레이어는 LOOP1의 레이블, 즉 후속 프로그램에서 LOOP1 레이블이 계속 문 또는 break 문에서 선택되면 가장 바깥 쪽 루프가 파손됩니다.
두 번째 레이어 루프는 최상위 루프의 LOOP2 라벨에 있습니다. LOOP2 레이블이 계속 명령문 또는 break 문에서 선택되면 최상위 루프의 루프 본체로 돌아갑니다.
루프 제어 명령문을 사용하면 원래 루프 실행 판단을 방해하여 매우 복잡한 논리 시스템을 구축 할 수 있습니다. 무뚝뚝하게 말하면 Linux 커널에는 많은 Goto 문장이 있습니다. 왜 당신이 여전히 Goto 진술과 같은 발언을 자주 듣는 지에 대해서는 직접 구글을 google하십시오.
5. 고급 루프
5.1 루프를 확장하십시오
먼저 두 코드를 살펴보고 어떤 코드가 더 나은 성능을 가진 코드를 추측합시다.
코드 사본은 다음과 같습니다.
// 설정
var array = [
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"], "Data"],
[ "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data", "Data"]]]]
];
기능 프로세스 (항목) {
// 항목으로 무언가를합니다
}
// 사례 1
for (var i = array.length-1; i> = 0; i-) {
for (var j = 배열 [i] .length-1; j> = 0; i-) {
프로세스 (배열 [i] [j]);
}
}
// 사례 2
for (var i = array.length -1; i> = 0; i = i -4) {
for (var j = 배열 [i] .length -1; j> = 0; j = j -6) {
프로세스 (배열 [i] [j]);
프로세스 (배열 [i] [j -1]);
프로세스 (배열 [i] [j -2]);
프로세스 (배열 [i] [j -3]);
프로세스 (배열 [i] [J -4]);
프로세스 (배열 [i] [j -5]);
}
for (var j = 배열 [i -1] .length -1; j> = 0; j = j -6) {
프로세스 (배열 [i] [j]);
프로세스 (배열 [i] [j -1]);
프로세스 (배열 [i] [j -2]);
프로세스 (배열 [i] [j -3]);
프로세스 (배열 [i] [J -4]);
프로세스 (배열 [i] [j -5]);
}
for (var j = 배열 [i -2] .length -1; j> = 0; j = j -6) {
프로세스 (배열 [i] [j]);
프로세스 (배열 [i] [j -1]);
프로세스 (배열 [i] [j -2]);
프로세스 (배열 [i] [j -3]);
프로세스 (배열 [i] [J -4]);
프로세스 (배열 [i] [j -5]);
}
for (var j = 배열 [i -3] .length -1; j> = 0; j = j -6) {
프로세스 (배열 [i] [j]);
프로세스 (배열 [i] [j -1]);
프로세스 (배열 [i] [j -2]);
프로세스 (배열 [i] [j -3]);
프로세스 (배열 [i] [J -4]);
프로세스 (배열 [i] [j -5]);
}
}
배열에서 서브 어레이의 모든 요소를 거쳐야합니다. 두 가지 솔루션이 있습니다. 하나는 우리가 일반적으로 사용하는 방법이며, 다른 하나는 루프 작업을 확장하는 것입니다. 대답은 6 개의 요소 간의 모든 실행 판단이 삭제되기 때문에 사례 2가 더 잘 수행된다는 것입니다. 이는 평소보다 자연스럽게 빠릅니다.
여기서 우리는보다 강력한 솔루션을 살펴 봅니다. 대형 데이터 세트에서 비즈니스 링크를 반복적으로 처리해야하고 반복 시작부터 데이터 볼륨이 변경되지 않으면 Duff 장치라는 기술을 사용하는 것을 고려할 수 있습니다. 이 기술은 제작자 인 Tom Duff의 이름을 따서 명명되었으며 C 언어로 처음 구현되었습니다. 나중에 Jeff Greenberg는이를 JavaScript로 포팅하여 Andrew B를 통해 수정했습니다. King과보다 효율적인 버전을 제안했습니다.
코드 사본은 다음과 같습니다.
// 크레딧 : 사이트 속도를 높이십시오 (New Riders, 2003)
var iterations = math.floor (vales.length / 8);
var leftover = values.length % 8;
var i = 0;
if (남은> 0) {
하다 {
프로세스 (값 [i ++]);
} while (-leftover> 0);
}
하다 {
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
프로세스 (값 [i ++]);
} while (-eritations> 0);
이 기술의 작동 원리는 8으로 나눈 값의 길이를 계산하여 반복 해야하는 반복의 수를 얻은 다음 Math.floor () 함수를 사용하여 결과가 정수가되도록 한 다음 8으로 나눌 수없는 숫자를 계산 한 다음 8 개를 별도로 처리하는 것입니다.
이 장치를 포장하고 비동기 맛이있는 API를 얻었습니다.
코드 사본은 다음과 같습니다.
함수 더프 (배열, 맵퍼) {
var n = math.floor (array.length / 8);
var l = array.length % 8;
var i = 0;
if (l> 0) {
하다 {
맵퍼 (배열 [i ++]);
} while (-i> 0);
}
하다 {
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
맵퍼 (배열 [i ++]);
} while (-n> 0);
}
더프 ([...], 함수 (항목) {
// ...
});
다음은 위의 세 가지 반복 솔루션에 대한 일련의 성능 테스트 및 결과입니다. http://jsperf.com/spread-loop
5.2 비 천연 루프
모든 프로그래밍 언어에서 루프는 다른 방식으로 간접적으로뿐만 아니라 다른 방식으로도 구현 될 수 있습니다.
먼저 고등학교 수학의 일부 내용 - 일반적인 시퀀스 공식을 검토합시다.
코드 사본은 다음과 같습니다.
기초적인
a [1] = 1
a [n] = 2 * a [n -1] + 1
그래서
A [N] + 1 = 2 * A [N -1] + 2
= 2 * (a [n -1] + 1)
(a [n] + 1) / (a [n -1] + 1) = 2
그 다음에
a [n] + 1 = (a [n] + 1) / (a [n -1] + 1) * (a [n -1] + 1) / (a [n -2] + 1) * ... * (a [2] + 1) / (a [1] + 1) * (a [i] + 1)
a [n] + 1 = 2 * 2 * ... * 2 * 2
a [n] + 1 = 2^n
a [n] = 2^n -1
결정적인
a [n] = 2^n -1
위의 간단한 계산을 읽은 후에는 우리가 무엇을 논의할지 추측 할 것입니다. 예, 재귀를 사용하여 루프를 구현할 수도 있습니다.
재귀는 수학 및 컴퓨터 과학에서 매우 중요한 응용 방법으로 사용될 때 자체 호출을하는 기능을 나타냅니다.
Node.js 커뮤니티에서 재귀는 매우 중요한 기술인 미들웨어 기술을 구현하는 데 사용됩니다. 이것은 아직 게시되지 않은 WebJS의 미들웨어 구현 코드의 새로운 버전입니다.
코드 사본은 다음과 같습니다.
/**
* 중간 전위 실행 방법
* @param {String} URL 현재 요청 URL입니다
* @param {object} Req 요청 객체를 req
* @param {object} res 응답 객체를 RES합니다
* @param {function} Out Complete Callback
* @return {function} 서버입니다
*/
server.runmiddlewares = function (url, req, res, out) {
var index = -1;
var middlewares = this._usingmiddlewares;
// 다음 미들웨어가 존재하면 실행합니다
기능 다음 (err) {
색인 ++;
// 현재 미들웨어
var cur = 중간 전쟁 [index];
if (curr) {
var check = 새로운 regexp (curr.route);
// 경로를 확인하십시오
if (check.test (url)) {
노력하다 {
나중에 기능 () {
디버그 ( '미들웨어는 나중에 %s', url에 있어야한다고 말합니다);
// 의존성은 지금 당장하지 않습니다
if (middlewares.indexof (curr)! == middlewares.length -1) {
_later (Curr);
색인--;
다음();
} 또 다른 {
디버그 ( '미들웨어 종속성 잘못');
//이 미들웨어는 실행할 수 없습니다
밖으로();
}
}
// 미들웨어를 실행합니다
if (utils.isfunc (curr.handler)) {
// 일반 미들웨어 기능
curr.handler (Req, res, next, 나중에);
} else if (utils.isobject (curr.handler) && utils.isfunc (curr.handler.emit)) {
// 서버 객체
curr.handler.emit ( 'request', req, res, next, 나중에);
} 또 다른 {
// 미들웨어에 대해 뭔가 잘못된 것이 있습니다
다음();
}
} catch (err) {
다음();
}
} 또 다른 {
다음();
}
} 또 다른 {
// 파이프 라인의 다음 단계로 나옵니다
밖으로();
}
}
// 미들웨어가 다른 중간 전쟁에 의존하는 경우
// 나중에 실행할 수 있습니다
함수 _later (curr) {
var i = middlewares.indexof (Curr);
var _tmp1 = middlewares.slice (0, i);
_TMP1.PUSH (중간 전위 [i + 1], Curr);
var _tmp2 = middlewares.slice (i + 2);
[] .push.apply (_tmp1, _tmp2);
중간 전위 = _tmp1;
}
// 첫 번째 미들웨어
다음();
이것을 반환하십시오;
};
이 코드는 가혹하고 복잡해 보이지만 단순화하면 훨씬 더 명확합니다.
코드 사본은 다음과 같습니다.
server.runmiddlewares = function (url, req, res, out) {
var index = -1;
var middlewares = this._usingmiddlewares;
// 다음 미들웨어가 존재하면 실행합니다
기능 다음 (err) {
색인 ++;
// 현재 미들웨어
var cur = 중간 전쟁 [index];
if (curr) {
var check = 새로운 regexp (curr.route);
// 경로를 확인하십시오
if (check.test (url)) {
// 현재 미들웨어를 실행합니다
curr.handler (Req, res, next);
} 또 다른 {
다음();
}
} 또 다른 {
// 파이프 라인의 다음 단계로 나옵니다
밖으로();
}
}
// 첫 번째 미들웨어
다음();
이것을 반환하십시오;
};
미들웨어 시스템의 구현에서 재귀를 사용할 수있는 이유는 재귀가 node.js에서 가장 적합한 프로그램 흐름 응답 방법이기 때문입니다.
이 미들웨어 구현 코드에서 this._usingmiddlewares는 루프 배열, Function Next ()는 루프 본문이며, 여기서 check.test (url)는 실행 판단 조건이고 루프 처리 코드는 루프 본문의 첫 번째 인덱스 카운터입니다.