2014-10-01 5 views
0

learnyounode의 도움으로 nodejs를 배웠고 Juggling Async에 머물러 있습니다. 내 솔루션은 문제의 가장 어려운 부분을 제외하고 작동합니다. 일부 요청은 다른 요청보다 먼저 완료되기 때문에 결과가 순서없이 인쇄됩니다. 헬퍼 라이브러리를 사용하지 않고이 작업을 수행하려고하므로 Google에 부딪 혔습니다. 컨트롤 플로우에 대한 훌륭한 튜토리얼을 발견했는데, 그의 비동기 함수가 정확히 1000ms를 기다리기 때문에 비동기 for 루프 전용의 그의 솔루션이 제대로 작동한다는 것을 알게되었습니다. 내 예제에서는 시간이 가변적이어서 동일한 순서로 결과를 얻지 못합니다. 이 예제는 제어 흐름 라이브러리를 작성하는 과정으로 들어가고 learnyounode 할당의 범위를 벗어나는 것처럼 작동하는 것처럼 느낍니다. 내가 시도저글링 비동기 - LearnYouNode - 즉각적인 함수 호출 표현

사항은 다음과 같습니다

는 URL, 순서 및 응답 데이터를 포함하는 객체 만들기. 내가 가진 문제는 http.get에 대한 콜백에 앉아있을 때 데이터를 가져 오는 URL을 알 수 없다는 것입니다. 이것은 실제로 내가 시도한 대부분의 잘못이며 콜백의 특정 URL로 돌아가는 데이터를 연결하는 방법을 알지 못합니다.

asyncCounter를 색인으로 사용하여 저장소 배열에 반환 된 데이터의 위치를 ​​구체적으로 설정하십시오. 그래서 이벤트 "end"가 발생하면 아래 코드에서 보는 바와 같이 설정합니다. 통화가 다른 시간에 끝나기 때문에 분명히 작동하지 않습니다.

결국 저는 해결책을 찾았습니다. 여기에 내가 가진 것이 있으며 별표가있는 내 솔루션에서 빠진 것을 표시했습니다.

var http = require("http"); 

var storage = []; 
var urlList = []; 
var asyncCounter = 0; 

//Store all the URL's from the command line in an array 
for(var i = 2; i < process.argv.length; i++){ 
    urlList.push(process.argv[i]); 
} 

//This function prints out all the data in the storage array 
//The storage array contains the data received from http.get 
function AsyncComplete(){ 
    for(var j = 0; j < storage.length; j++){ 
     console.log(storage[j]); 
    }; 
}; 

//Entry function 
function main(){ 
    //Do an http get on each of the provided URL's 
    for(var i = 0; i < urlList.length; i++){ 
     **(function(i){** 
      http.get(urlList[i], function(response){ 
       var body = ""; 
       //Got a chunk of data! 
       response.on("data", function(chunk){ 
        body += chunk; 
       }); 
       //All done with our request. 
       response.on("end", function(){ 
        //Store the total response from the URL 
        storage[**i**] = body; 
        asyncCounter++; 
        //Check if we can print the results yet 
        //I want to wait for all the calls to complete so I am using a counter 
        if(asyncCounter == urlList.length){ 
         AsyncComplete(); 
        } 
       }); 
      }); 
     **})(i);** 
    }; 
}; 

main(); 

그래서 나는 그들이 무엇을하는지 전혀 몰랐기 때문에 다시 구글을 쳤다. 그리고 나는 closure라고 불리는 것을 발견했다. 내 이해에서, 그들이 한 일은 콜백의 범위에 머물러 있습니다. 나는 그렇게 생각하는 방법을 생각할 수 없었습니다. 일찍 불가능하고 버려진 생각이었습니다.

제 질문은 정확하게 작동하는 것입니다. 특히 (i) 그들이하는 곳과 제공하는 목적이 무엇인지 궁금합니다. 그 해결책은 (i) 없이는 작동하지 않습니다. 왜 당신은 단지 (함수 (i) {어딘가에) 함수를 던질 수 있습니까? 이것은 백만 년 동안 생각하지 못했던 것입니다.

나는 https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Closures을 찾았습니다. 내가 뭔가 가지고 올 수 있다면 그 사이에 그 읽어 볼 것.

감사를 사전에 시간!

스티브.이는 즉시 호출 기능 식 (인생)라고

답변

2

즉시 호출되는 익명의 함수입니다.이 IIFE에 건네지는 파라미터 i는, 호출 스택에 넣고 for 루프의 외부 i와는 다른 것입니다. 현재 i의 스냅 샷을 생성하는 것처럼 상상할 수 있습니다.

"var"로 선언 된 JavaScript 변수의 범위는 기능 범위입니다. 따라서 모든 콜백은 동일한 i (원하는 것은 아닙니다)에 액세스합니다. 이를 IIFE (함수이고 따라서 변수 i에 대한 자체 범위를 도입 함)에 전달함으로써 각 콜백에 대해 새로운 변수가 작성됩니다. IIFE의 매개 변수에 다른 이름을 지정하면 더 명확 해집니다.예를 들어

(function(savedI) { // ... })(i)

파라미터를 I 네이밍함으로써, 일본어 나 섀도우이다. 즉, IIFE 내부의 "외부"i는 액세스 할 수 없습니다.

IIFE를 사용하는 일반적인 대안은 대신 지도을 사용하는 것입니다. 예를 들어

_.range(urlList.length).map(function(i) { // ... })

_.range는 underscore에서 유틸리티 함수와 0 내지 urlList.length까지 도달하는 배열을 제공한다. 전달 된 함수는 매개 변수 i를받습니다. 매개 변수 i는 재정의되지 않습니다 (for 루프는 해당 버전에서 수행 한 것과 같습니다).

또 다른 가능성은 을 통해 변수를 선언하는 것이 EcmaScript 6 이상에서 가능한이라고 할 수 있습니다. 이렇게하면 블록 범위 변수가 생깁니다. 자세한 내용은 here을 참조하십시오. 예 :

for(let i = 0; i < urlList.length; i++){ // .. }

+0

의견을 보내 주셔서 감사합니다. 내 질문에 완벽하게 답변. 나는 완전히 잘못된 것을보고 있었다. - .- – Steve