Node.js-异步-if语句中的多个内部回调 [英] Node.js - Async - multiple innercallbacks within a if statement
问题描述
我正在使用Node.js和异步库,但是我一直看到错误:Callback was already called
.
I'm using Node.js and the async library, however I keep seeing the error: Callback was already called
.
我想我理解为什么会收到该错误,但是我不知道是否真的可以执行以下操作/如何解决.
I think I understand why I get the error, however I don't know if it is actually possible to do the following/how can resolve.
基本上,我希望两个内部回调都在外部回调完成之前完成.
Basically I want both the innercallbacks to have completed before the outercallback is completed.
所以我面对这个问题的代码如下:
So the code with which I am facing this issue looks like:
async.forEachLimit(inData, 25, function (data, innercallback) {
myJson.matches.forEach(function (oMatches) {
if (data.$.id == oMatches.SourceId) {
oMatches.ids.forEach(function (odId) {
client.execute("g.addV('test').property('id', \"" + data.$.id + "\")", {},
function (err) {
setTimeout(function () { innercallback(err) }, 2000);
});
client.execute("g.V('" + data.$.id + "').addE('matches').to(g.V('xyz'))", {},
function (err) {
setTimeout(function () { innercallback(err) }, 2000);
});
})
} //there is no else case.
});
}, outercallback);
顺便说一句-我正在使用setTimeout
和async.forEachLimit
来减少对Azure的请求数量(因为我没有太多)
Btw - I'm using setTimeout
along with async.forEachLimit
to reduce number of requests made to Azure (as I don't have too many)
推荐答案
Promise can be used to ensure the order of asynchronized callbacks.
看看官方文档中的 async#AsyncFunction
async
包
Take a look at async#AsyncFunction
in the official document
of async
package
无论我们接受Node样式的异步功能,我们也直接 接受ES2017异步功能.在这种情况下,异步功能将 不会传递最终的回调参数,并且将抛出任何错误 用作隐式回调的err参数,并返回 值将用作结果值. (即拒绝 返回的Promise成为err回调参数,并且已解决 值成为结果.)
Wherever we accept a Node-style async function, we also directly accept an ES2017 async function. In this case, the async function will not be passed a final callback argument, and any thrown error will be used as the err argument of the implicit callback, and the return value will be used as the result value. (i.e. a rejected of the returned Promise becomes the err callback argument, and a resolved value becomes the result.)
async#forEachLimit
的第三个参数是async#AsyncFunction
因此您可以从中返回一个承诺,然后再解决该承诺以表明其工作已完成.
The third argument of the async#forEachLimit
is an async#AsyncFunction
so you can just return a promise from it and later resolve the promise to indicate that its job has finished.
您的代码可以进行如下改进,
Your code can be improved as follows,
async.forEachLimit(inData, 25, function (data, innercallback) {
// we will wait for all async function in here to complete
// then call the innercallback
var asyncPromises = []
myJson.matches.forEach(function (oMatches) {
if (data.$.id == oMatches.SourceId) {
oMatches.ids.forEach(function (odId) {
asyncPromises.push(new Promise(function (resolve, reject) {
client.execute("g.addV('test').property('id', \"" + data.$.id + "\")", {},
function (err) {
setTimeout(function () {
if (err) {
reject(err)
return
}
resolve();
}, 2000);
});
}))
asyncPromises.push(new Promise(function (resolve, reject) {
client.execute("g.V('" + data.$.id + "').addE('matches').to(g.V('xyz'))", {},
function (err) {
setTimeout(function () {
if (err) {
reject(err)
return
}
resolve();
}, 2000);
});
}))
})
} //there is no else case.
})
// Here we can ensure that innercallback is called only for once
Promise.all(asyncPromises)
.then(function () {
innercallback(null)
})
.catch(function (err) {
// handle the error here
innercallback(err)
})
}, outercallback);
请注意,您应确保在Node环境中获得Promise
支持.节点v6之后支持内置Promise
.在此处.
Note that you should make sure you have Promise
support in your Node environment. Builtin Promise
is supported after Node v6. Check out here.
已更新
我误解了您在调用externalcallback之前必须完成的内部回调.我已经用Promise.all
对其进行了更正,它以Promise
数组作为参数并返回一个Promise
,如果所有子Promise
都被解析或被拒绝,而子<Promise#all
.
I've misunderstood you internal callbacks which both of them must have completed before outercallback is called. I've corrected it with Promise.all
, which takes an array of Promise
as arguments and return a Promise
which will be resolved if all sub-Promise
s are all resolved or rejected if one of sub-Promise
s is rejected. See Promise#all
.
已更新(2018.05.14)
您必须确保从async
包的AsyncFunction(即async#forEachLimit
的第三个参数)接收到的每个innercallback
在每次迭代期间仅被调用一次一次.特别是在每次迭代中执行Array#forEach
时要小心,因为这可能会使您在一次迭代中多次调用innercallback
.
You have to ensure that every innercallback
received from AsyncFunction (i.e. the 3rd argument of async#forEachLimit
) of the async
package is called only once during each iteration. Especially to be careful when you do Array#forEach
in each iteration since it may make you call innercallback
multiple times in an iteration.
我已经更新了上面的代码块,在这里我从client.execute
的回调中删除了对innercallback
的所有调用,并将所有client.execute
放入了promise中.之后,我将所有的承诺收集到asyncPromises
数组中.
Promise#all
用于确保所有承诺均已解决(即所有client.execute
已完成),然后最终调用innercallback
.或者,如果上述承诺中的一个被拒绝并被捕获在Promise#catch
中,请使用第一个参数作为错误原因调用innercallback
.
I've update the code block above, where I take away all calls to innercallback
from the callback of client.execute
and put all client.execute
into a promise. After that I collect all promises into the asyncPromises
array.
Promise#all
is used to ensure that all promises are resolved (i.e. all client.execute
s are finished) then finally call innercallback
. Or if one of the promise above is rejected and is caught in Promise#catch
, call innercallback
with the first argument to be the error reason.
这篇关于Node.js-异步-if语句中的多个内部回调的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!