Javascript forEach循环中的异步函数和回调
在该功能中:Javascript forEach循环中的异步函数和回调,javascript,node.js,Javascript,Node.js,在该功能中: 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 call
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)
不起作用,在最后一次回调时,一个空的
返回一个数组。为什么呢李>
返回回调('Error')
从未被调用<代码>返回回调(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)
}
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);
}
});
});
}
Example([1, 2, 3]).then(
function(results) {
// ...
},
function(error) {
// ...
}
);
由于调用了多个回调,脚本崩溃。forEach为什么这样做?如何避免?您的问题
toReturn.push(doc)不工作,在最后一次回调时返回一个空数组。为什么呢
您在MongooseModel之前调用callback
。AsyncFunction
有机会执行函数(err,doc)
如果有错误,或者!如果docs为true,则不会调用return callback('Error')。始终调用返回回调(null,toReturn)
在调度异步函数后,将立即调用成功返回。MongooseModel.AsyncFunction
仍有可能稍后调用回调('Error')
由于调用了多个回调,脚本崩溃
这正是你要求的行为!您的第二个代码字面上说:“对于每个元素,调用回调一次”
一些指针 总而言之,我认为您唯一的错误是调用回调有点像从函数返回 事实并非如此!您的函数
示例
应该安排一些异步事件发生,然后立即返回(不返回任何内容),但承诺将来某个时候调用回调(错误)
或回调(null,成功)
因此,说returncallback()
,没有任何意义——只要callback()
就行了。当您有一些数据要调用callback
时,函数Example
将已经完成执行。最终调用回调
的函数将是传递给MongooseModel.AsyncFunction
的匿名函数,而不是示例
本身
现在怎么办? 您可以尝试以下方法:
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)
}
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);
}
});
});
}
Example([1, 2, 3]).then(
function(results) {
// ...
},
function(error) {
// ...
}
);
这里发生的事情:
- 每次
完成时,都会聚合结果。如果这是最后一个,您最终可以调用AsyncFunction
并传递整个数据。(否则,我们将等待更多的函数,因此没有callback
)回调
- 如果在执行过程中出现了错误,我们会立即报告,但也要注意,错误已经报告过了,因此已计划的
的进一步执行不会做任何特别的事情。这可以防止您的asyncfonment
可能被调用两次或多次回调
- 不过要小心,
中元素的顺序是随机的,这取决于先完成的异步任务toReturn
但这很混乱 哦,是的。这就是为什么我们不再真正进行回调。有一种称为的模式,它使异步回调意大利面的使用变得非常简单,我建议在继续之前先阅读一下这个主题
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 {
// ...
}
})
你这样称呼:
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)
}
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);
}
});
});
}
Example([1, 2, 3]).then(
function(results) {
// ...
},
function(error) {
// ...
}
);
哦,这依赖于MongooseModel.AsyncFunction
本身返回承诺,但大多数库也是如此。如果库不支持,您可以轻松添加promise支持(参见示例)
如何在返回异步函数的每个结果之前对其执行操作?
也很容易
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);
}
将返回一个被拒绝的承诺视为类似于引发异常的事情—它自然会一直冒泡到
示例的返回承诺
您应该使用承诺,因为您需要等待所有异步调用完成后再返回结果。下面是一个例子:
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');
});
}
在这里,您可以阅读有关承诺的更多信息:基本上,您的函数按以下顺序执行:
数组中的每个元素触发异步操作
async.parallel(array.map(function() {
return MongooseModel.AsyncFunction(...)
}), function(err, results) {
// all the async calls are finished, do something with the results
});
“toReturn.push(doc)不起作用,在最后一次回调时返回一个空数组。这是为什么?”它起作用了。但是
回调(null,toReturn)
是在toReturn.push(doc)
有机会执行之前执行的。您似乎已经知道了原因:因为在forEach
回调中执行的代码是异步的。看一看,了解更多。其中一个可能会有帮助:。这不是总是拒绝承诺吗?另外,我认为应该返回承诺,而不是让函数接受回调(当然这取决于OP的情况)。更新了commentBrr,您提供了一个带有承诺的示例,这很酷,但您没有真正使用类似于Promise.all()
的任何东西,这将真正简化此问题