[英]Async function and callbacks inside a forEach loop
在這個功能里面:
function Example(array, callback){
var toReturn = [];
// variable 'array' has 2 elements in this case
array.forEach(function(el){
MongooseModel.AsyncFunction(el, function(err, doc){
if(err || !doc){ return callback('Error'); }
toReturn.push(doc)
});
});
return callback(null, toReturn)
}
有幾點需要注意:
toReturn.push(doc)
不起作用,在最后一個回調中返回一個空數組。 這是為什么? return callback('Error')
。 始終調用return callback(null, toReturn)
。 另外,如果我在異步函數上面放回調,如下所示:
function Example(array, callback){
var toReturn = [];
// variable 'array' has 2 elements in this case
array.forEach(function(el){
// another callback here
return callback('Error')
MongooseModel.AsyncFunction(el, function(err, doc){
if(err || !doc){ return callback('Error'); }
toReturn.push(doc)
});
});
return callback(null, toReturn)
}
腳本崩潰,因為已經調用了多個回調。 為什么每個人都這樣做以及如何避免它?
toReturn.push(doc)不起作用,在最后一個回調中返回一個空數組。 這是為什么?
你在MongooseModel.AsyncFunction
之前調用callback
MongooseModel.AsyncFunction
有機會執行你的function(err,doc)
。
如果出現錯誤,或者!docs為true,則永遠不會調用return callback('Error')。 始終調用return callback(null,toReturn)。
在安排異步功能后立即調用成功返回。 MongooseModel.AsyncFunction
稍后可能會調用callback('Error')
。
腳本崩潰,因為已經調用了多個回調
這正是你要求的行為! 您的第二個代碼字面上說:“對於每個元素,請調用一次回調”。
總而言之,我認為你唯一錯誤的是調用回調有點類似於從函數返回。
事實並非如此! 您的函數Example
應該安排一些異步事件發生,然后立即返回(不返回任何內容),但承諾將來稍后將調用callback(error)
或callback(null, success)
。
因此,永遠不要說return callback()
- 只是callback()
會這樣做。 當您有一些數據要調用callback
時,函數Example
已經完成執行。 最終調用callback
的函數將傳遞給MongooseModel.AsyncFunction
的匿名函數,而不是Example
本身。
您可以嘗試這樣的方法:
function Example(array, callback){
var toReturn = [];
var previousError = false;
array.forEach(function(el){
MongooseModel.AsyncFunction(el, function(err, doc){
if (previousError) {
return;
}
if(err || !doc) {
previousError = true;
callback('Error');
}
toReturn.push(doc)
if (toReturn.length === array.length) {
// that was the last push - we have completed
callback(null, toReturn);
}
});
});
}
發生在這里的東西:
每次AsyncFunction
完成時,都會聚合結果。 如果那是最后一個,你最終可以調用callback
並傳遞整個數據。 (否則,我們正在等待更多功能,所以沒有callback
)
如果在此過程中某處出現錯誤,我們會立即報告,但也要注意已經報告錯誤,以便進一步執行已安排的AsyncFunction
特別沒有做任何事情。 這可以防止您的callback
被調用兩次或更多次。
但請注意 - toReturn
的元素toReturn
將是隨機的,具體取決於首先完成的異步任務。
哦,是的。 這就是為什么我們不再做回調了。 有一種稱為promises
的模式使得使用異步回調意大利面更加容易,我建議在繼續前進之前先閱讀一下這個主題。
使用promises,這種代碼看起來像:
function Example(array) {
var promises = array.map(function(el) {
return MongooseModel.AsyncFunction(el);
});
return Promise.all(promises);
}
這比我們前面的例子中的錯誤處理或輸出項的排序沒有任何問題。
用法很簡單 - 而不是這個
Example([1, 2, 3], function(error, results) {
if (error !== null) {
// ...
} else {
// ...
}
})
你這樣打電話:
Example([1, 2, 3]).then(
function(results) {
// ...
},
function(error) {
// ...
}
);
哦,這依賴於MongooseModel.AsyncFunction
返回一個自己的承諾,但是Mongoose已經這樣做了,大多數庫也是如此。 如果庫沒有,您可以輕松添加promise支持(例如,參見NodeRedis )。
如何在返回之前對AsyncFunction
每個結果AsyncFunction
什么?
很容易!
function Example(array) {
var promises = array.map(function(el) {
return MongooseModel.AsyncFunction(el).then(function(doc) {
return doc + "some modifications";
});
});
return Promise.all(promises);
}
或者,如果您需要其他錯誤處理:
function Example(array) {
var promises = array.map(function(el) {
return MongooseModel.AsyncFunction(el).then(function(doc) {
if (theresSomethingWrongWith(doc) {
return Promise.reject(new Error("ouch!"));
}
return doc + "some modifications";
});
});
return Promise.all(promises);
}
想一想將被拒絕的承諾歸為類似於引發異常的東西 - 它會自然地冒出一直到Example
的返回承諾。
基本上,您的函數按以下順序執行:
array
每個元素的異步操作 要執行多個異步調用並返回結果,您需要等待所有這些調用完成。 我通常在庫異步的幫助下解決這個問題,甚至可以讓你控制異步調用應該如何執行(串行或並行)。 例如,您可以使用異步函數數組調用async.parallel :
async.parallel(array.map(function() {
return MongooseModel.AsyncFunction(...)
}), function(err, results) {
// all the async calls are finished, do something with the results
});
您應該使用promises,因為在返回結果之前需要等待所有異步調用。 這是一個例子:
function Example(array, callback){
new Promise(function(resolve, reject) {
var toReturn = [];
array.forEach(function(el){
MongooseModel.AsyncFunction(el, function(err, doc){
if(err || !doc) {
return reject();
}
toReturn.push(doc);
if (toReturn.length === array.length) {
resolve(toReturn);
}
});
});
})
.then(callback)
.catch(function() {
callback('error');
});
}
在這里,您可以閱讀有關承諾的更多信息: https : //developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Promise
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.