Node.js-异步-if语句中的多个内部回调 [英] Node.js - Async - multiple innercallbacks within a if statement

查看:117
本文介绍了Node.js-异步-if语句中的多个内部回调的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用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);

顺便说一句-我正在使用setTimeoutasync.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都被解析或被拒绝,而子< s被拒绝.请参见 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-Promises are all resolved or rejected if one of sub-Promises 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.executes 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆