2017-04-18 72 views
-1

我正在使用forEach()循環遍歷ARRAY。 對於每個元素,我需要調用一個請求。 我想在所有調用的請求完成後(假設我至少有100個調用請求)調用next()。NODE.JS - 如何在多個請求完成後正確調用next()?

任何想法如何解決這個問題?

這裏是一個小示例代碼來演示我的問題 -

var arr = ["A" , "B", "C" , "D" , "E"]; 
 
arr.forEach(function (arrayItem) { 
 
\t var options = { 
 
     method: 'GET', 
 
     url:"some_url", 
 
     headers: {...} 
 
    }; 
 
    request(options, function (error, response, body) 
 
    { 
 
    if (error) {next(error);} 
 

 
    // DO_SOMETHING based on arrayItem 
 

 
    }); // end of request() 
 
}); //end of forEach 
 

 
// WHERE should I place the next()?

回答

1

有幾個方法可以做到這一點。由於所有對request()的調用都是異步的,因此在循環結束後很長一段時間內會完成,因此您必須以某種方式跟蹤它們。我將展示兩種方法,一種使用Promise,另一種使用計數器。

承諾

// create wrapper function that returns a promise 
function requestPromise(options) { 
    return new Promise(function(resolve, reject) { 
     request(options, function(error, response, body) { 
      if (error) return reject(error); 
      resolve({response: response, body: body}); 
     }); 
    }); 
} 

var arr = ["A" , "B", "C" , "D" , "E"]; 

Promise.all(arr.map(function(item) { 
    // create options object here for each request 
    var options = { 
     method: 'GET', 
     url:"some_url", 
     headers: {...} 
    }; 

    return requestPromise(options); 

})).then(function(results) { 
    // process results here 

    // call next() here because all processing is now done 
    next(); 
}).catch(function(err) { 
    // error happened 
    next(err); 
}); 

手動計數器

var arr = ["A" , "B", "C" , "D" , "E"]; 
var errDone = false; 
var cntr = 0; 
arr.forEach(function (arrayItem) { 
    var options = { 
     method: 'GET', 
     url:"some_url", 
     headers: {...} 
    }; 
    request(options, function (error, response, body) { 
    if (error) { 
     if (!errDone) { 
      // latch error so we don't call next(error) multiple times 
      errDone = true; 
      next(error); 
     } 
    } else { 
     // process result here 

     // check if this is the last response 
     ++cntr; 
     if (cntr === arr.length) { 
      // all responses done here 
      next(); 
     } 
    } 
    }); 
+0

嗨@ jfriend00--非常感謝,它的確幫助我理解了這個對我來說完全陌生的概念。 只是關於你的解決方案的一個小問題 - 在catch()方法上,錯誤會包括失敗請求的具體響應,以及它的所有細節(所以我會知道哪個請求失敗),還是隻包含錯誤的迴應消息? –

+0

@GadiBenAmram - 它將包含'request()'中的'error'值,它首先失敗。如果你願意,你可以包含更多的信息,只需構建自己的對象並添加更多信息,並調用'reject(yourObj)'而不是'reject(error)'。 – jfriend00

+0

明白了!再次感謝@ jfriend00,它確實幫助:-)。 –

1

我會建議你使用這個承諾。

數組中的每個元素都是一個Promise,在完成所有事情之後,調用一個.then()函數。

對於您的情況:

Promise.all()將是最好的解決方案。 https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

用法:

var A = new Promise((resolve, reject) => { 
    var options = { 
     method: 'GET', 
     url:"some_url", 
     headers: {...} 
request(options, function (error, response, body) 
    { 
    if (error) {reject()}; 
    resolve(); 
    }); 
}); 
var B = new Promise((resolve, reject) => { 
    var options = { 
     method: 'GET', 
     url:"some_url", 
     headers: {...} 
request(options, function (error, response, body) 
    { 
    if (error) {reject()}; 
    resolve(); 
    }); 
}); 
var arr = [A , B, C , D , E]; 
Promise.all(arr).then(next()); 
+0

嘿@ Hardik,耆那教,非常感謝。 我選擇標記另一個答案是解決方案,因爲它也有助於解決大數組(超過100個元素)的映射問題,但您的答案也幫助我理解如何處理解決方案,我非常感謝您花時間並努力寫出如此出色的迴應。 再次感謝:-)。 嘎迪。 –

+0

很高興幫助! :D –

相關問題