[英]node.js multiple asynchronous functions
var http = require('http');
var res = ["","",""];
for(i =2;i<5;i++){
http.get(process.argv[i],function(response){
response.setEncoding('utf8');
str = "";
count =i-2;
response.on("data", function(data) {
str = str.concat(data);
});
response.on("end", function() {
res[count] = str;
console.log(count);
console.log(res[count]);
});
});
}
while(true) {
if(res[0]!==""&&res[1]!==""&&res[2]!=="")
{
console.log(res[0]);
console.log(res[1]);
console.log(res[2]);
break;
}
}
我將使用三個 URL 作為前三個命令行參數。 我的工作是從每個 URL 中收集作為字符串的數據,並按照它們在命令行中出現的順序將它們打印到控制台。 現在代碼沒有打印任何東西,它陷入了無限循環。 怎么了?
代碼中有兩個問題。 首先,您在循環變量上有一個閉包,這使得值與 guvinder372 解釋的預期不同。 另見這個答案,其中討論了這個問題,這個答案演示一種更好的方式使用來解決這個問題Function.bind
。
第二個問題是你在最后設置你的while
循環的方式。 該循環將持續運行,並且永遠不會允許http.get
的回調函數運行。 相反,如果其他響應已經進入,則檢查回調,一旦所有三個響應都進入,打印輸出。
for(i =2;i<5;i++){
http.get(process.argv[i],function(response){
response.setEncoding('utf8');
str = "";
count =i-2;
response.on("data", function(data) {
str = str.concat(data);
});
response.on("end", function() {
//Check here if responses are in
if(res[0]!==""&&res[1]!==""&&res[2]!=="") {
}
res[count] = str;
console.log(count);
console.log(res[count]);
});
});
}
問題是- 調用回調處理程序時, i 的值已經達到 5 並且對於所有回調處理程序執行它將保持為 5。
您需要重構代碼以將 i 的值傳遞給該調用方法
var http = require('http');
var res = ["","",""];
for(i =2;i<5;i++)
{
callBackDefiner(i)
}
function callBackDefiner( i )
{
http.get(process.argv[i],function(response){
response.setEncoding('utf8');
str = "";
count =i-2;
response.on("data", function(data) {
str = str.concat(data);
});
response.on("end", function() {
res[count] = str;
console.log(count);
console.log(res[count]);
});
});
}
您不能在不等待響應的情況下在for...loop
循環中執行多個 http 請求。 要以現代方式編寫此代碼,您需要一些新的構造/模式,例如Promise
。 然后,您可以等待每個響應、收集響應並退出調用者。 舉個例子,看看我的 javascript 客戶端解決方案。 這也可以在Node.js
進行少量工作,您只需更改在塊函數ExecutionBlock
請求的方式即可。
假設我們有一個我們想要發送到一些 urls / 或不同 url 數組的參數數組,我們將使用Promise.all
構造運行。
在以下代碼段中嘗試一下。
要了解如何將此解決方案應用於Node.js
請在此處查看我對http
get 和 post 的實現,並在本文后面查看異步任務節點中更復雜的執行。
var console = { log: function(s) { document.getElementById("console").innerHTML += s + "<br/>" } } // Simple XMLHttpRequest // based on https://davidwalsh.name/xmlhttprequest SimpleRequest = { call: function(what, response) { var request; if (window.XMLHttpRequest) { // Mozilla, Safari, ... request = new XMLHttpRequest(); } else if (window.ActiveXObject) { // IE try { request = new ActiveXObject('Msxml2.XMLHTTP'); } catch (e) { try { request = new ActiveXObject('Microsoft.XMLHTTP'); } catch (e) {} } } // state changes request.onreadystatechange = function() { if (request.readyState === 4) { // done if (request.status === 200) { // complete response(request.responseText) } else response(); } } request.open('GET', what, true); request.send(null); } } //PromiseAll var promiseAll = function(items, block) { var self = this; var promises = [], index = 0; items.forEach(function(item) { promises.push(function(item, i) { return new Promise(function(resolve, reject) { if (block) { block.apply(this, [item, index, resolve, reject]); } }); }(item, ++index)) }); return Promise.all(promises) }; //promiseAll // LP: deferred execution block var ExecutionBlock = function(item, index, resolve, reject) { SimpleRequest.call('https://icanhazip.com/', function(result) { if (result) { console.log("Response[" + index + "] " + result); resolve(result); } else { reject(new Error("call error")); } }) } arr = [1, 2, 3] promiseAll(arr, (item, index, resolve, reject) => { console.log("Making request [" + index + "]") ExecutionBlock(item, index, resolve, reject); }) .then((results) => { console.log(results) }) .catch((error) => { console.error(error) });
<div id="console" />
對於通過Promise
和Promise.all
應用於 node.js 的類似方法,請參閱我的問題here 。 這是關於以異步方式在節點中生成通用進程的執行。
這里有一個更復雜的例子,展示了如何使用Promise
在N * M
http.get
執行器中生成和鏈接多個級別的 http 調用執行。 因此,您將開始執行N
請求,每個請求將啟動M
請求,感謝Promise.all
您將等待每個請求,等待第一個M
所有結果,然后是N * M
個請求響應數組的所有結果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.