Node.js-Async-if语句中的多个InnerCallback
我正在使用Node.js和异步库,但是我一直看到错误:Node.js-Async-if语句中的多个InnerCallback,node.js,azure-cosmosdb,gremlin,async.js,Node.js,Azure Cosmosdb,Gremlin,Async.js,我正在使用Node.js和异步库,但是我一直看到错误:回调已被调用 我想我理解我为什么会出错,但是我不知道是否真的可以做到以下几点/如何解决 基本上,我希望在完成outercallback之前完成两个InnerCallback 因此,我面临这个问题的代码如下所示: async.forEachLimit(inData, 25, function (data, innercallback) { myJson.matches.forEach(function (oMatches) {
回调已被调用
我想我理解我为什么会出错,但是我不知道是否真的可以做到以下几点/如何解决
基本上,我希望在完成outercallback之前完成两个InnerCallback
因此,我面临这个问题的代码如下所示:
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的请求数量(因为我没有太多)可以用来确保异步回调的顺序
看看
异步包的
无论我们在哪里接受节点样式的异步函数,我们也直接
接受ES2017异步函数。在这种情况下,异步函数将
不会传递最终回调参数,任何抛出的错误都将
用作隐式回调的err参数,并返回
值将用作结果值。(即被拒绝的
返回的承诺将成为err回调参数,并且
值成为结果。)
的第三个参数是一个async#async函数
,因此您只需从它返回一个承诺,然后解析该承诺,以指示其工作已完成
您的代码可以改进如下:
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);
请注意,您应该确保节点环境中有Promise
支持。节点v6之后支持内置Promise
。退房
已更新
我误解了您的内部回调,它们必须在调用outercallback之前完成。我已经用Promise.all
对其进行了更正,它将Promise
数组作为参数,并返回一个Promise
,如果所有子Promise
都已解决,则该问题将得到解决;如果其中一个子Promise
被拒绝,则该问题将被拒绝。看
更新(2018.05.14)
您必须确保从AsyncFunction(即,async#forEachLimit
包的innercallback
的第三个参数)接收到的每个async
包在每次迭代期间只调用一次。尤其是在每次迭代中执行Array#forEach
时要小心,因为它可能会使您在迭代中多次调用innercallback
我已经更新了上面的代码块,从client.execute
的回调中删除对innercallback
的所有调用,并将所有client.execute
放入一个承诺中。之后,我将所有承诺收集到asyncPromissions
数组中。
Promise#all
用于确保所有承诺都已解决(即所有client.execute
s已完成),然后最后调用innercallback
。或者,如果上面的一个承诺被拒绝,并且在promise#catch
中被捕获,则调用innercallback
,第一个参数作为错误原因。如果两个客户端都出现错误,则调用innercallback
两次。执行
抛出错误。您可以使用function或Promise.all
,这里是async.parallel
的示例,您还需要在else
块中调用innercallback
函数
async.forEachLimit(inData, 25, function(data, innercallback) {
async.eachSeries(myJson.matches, function(oMatches, callback) {
if (data.$.id == oMatches.SourceId) {
async.eachSeries(oMatches.ids, function(odId, callback) {
async.parallel([
function(callback) {
client.execute("g.addV('test').property('id', \"" + data.$.id + "\")", {}, callback);
},
function(callback) {
client.execute("g.V('" + data.$.id + "').addE('matches').to(g.V('xyz'))", {}, callback);
}
], callback);
}, callback)
} else {
callback();
}
}, innercallback);
}, outercallback);
更新:更新了代码,现在在
数组的位置使用async.eachSeries
。forEach
尝试一下?我已经更新了代码。如果有任何问题,请告诉我。这不起作用-仍然获取已调用的回调
errorError-RangeError:最大调用堆栈大小exceeded@userMod2callback()
->process.nextTick(函数(){callback()})
@SergeyLapin谢谢,这样就消除了最大调用堆栈大小错误-但是它实际上运行的是g.addV('test')
第二行gremlinquery@SergeyLapin-我不能做类似innercallback
和innercallback2
的事情吗?哦,我明白了。每次迭代中的innercallback
只能调用一次。我会为此更新代码。