【问题标题】:Async function works when called once but not multiple occasions异步函数在调用一次但不是多次调用时有效
【发布时间】:2014-05-06 03:29:51
【问题描述】:

我使用 async.waterfall 来展平嵌套函数,如下所示。

function convertPortfolio(trademarks, fn){
    async.waterfall([function(callback){
        groupByCountry(trademarks, callback)
    },
    function(TMsGroupedByCountry, callback){
        addEUTrademarks(TMsGroupedByCountry['EU'], TMsGroupedByCountry, callback)
    },
    function(revisedGroupByCountry, callback){
        groupTrademarksByStatus(revisedGroupByCountry, callback)

    }], function(err, splitByStatus){
        fn(null, splitByStatus);
    })
}

嵌套替代

function convertPortfolio(trademarks, fn){
    groupByCountry(trademarks, function(err, TMsGroupedByCountry){
        addEUTrademarks(TMsGroupedByCountry['EU'], TMsGroupedByCountry,   function(err, revisedGroupByCountry){
            groupTrademarksByStatus(revisedGroupByCountry, function(err, splitByStatus){
                 fn(null, splitByStatus)
            });
        });
    });
 }

随后,当我将此函数作为另一个函数的一部分调用一次时,它可以完美运行。但是,当我尝试使用数组上的 forEach 调用中的单独值多次调用该函数时,当嵌套版本正常工作时,它无法工作。我不知道为什么会这样,老实说,我不知道从哪里开始。我的理解是,forEach 调用应该只是意味着每个单独的值都会被相应地处理并关闭,所以这不应该是问题。

异步函数正常工作并在此实例中返回值

exports.convertPortfolioAndAddToGeoJSON = function(geojson, trademarks, fn){
   convertPortfolio(trademarks, function(err, revisedTMs){
    addToGeoJson(geojson, revisedTMs, function(err, gj){
        fn(null, gj)
      });
   });
}

但在这种情况下,最终目标对象没有被填充:

exports.convertYearPortfolioAndAddToGeoJSON = function(geojson, trademarks, fn){
  var target = {};
  Object.keys(trademarks).forEach(function(year){
    convertPortfolio(trademarks[year], function(err, revisedTMs){
        addToGeoJson(geojson, revisedTMs, function(err, revisedGeoJSON){
            target[year] = revisedGeoJSON;
            });
        });
    });
    fn(null, target);
  }

在某些点使用 console.log 表明,在嵌套示例中,在记录目标对象之前记录返回值,而在 async.waterfall 示例中,在返回数据可用之前记录目标对象(所以我认为记录目标会导致空对象并不奇怪)。

我认为在每种情况下,回调的存在意味着目标的日志记录只会在之前所有处理完成后才会发生,但尽管嵌套替代方案似乎是这种情况,但事实并非如此至少在多次调用时使用异步版本。

任何指导将不胜感激。

更新出于兴趣,这里是使用 async.forEach 修改后的代码:

exports.convertYearPortfolioAndAddToGeoJSON = function(geojson, trademarks, fn){
  var target = {};
  async.forEach(Object.keys(trademarks), function(year, callback){
    async.waterfall([
        async.apply(convertPortfolio, trademarks[year]),
        function(revisedTMs, callback){
            addToGeoJson(geojson, revisedTMs, callback)
        }], 
        function(err, revisedGeoJSON){
            target[year] = revisedGeoJSON;
            callback()
        })
   }, function(err){
       fn(null, target);
   });
}

【问题讨论】:

    标签: javascript node.js async.js


    【解决方案1】:

    Object.keys(trademarks).forEach 是同步的,不能正确跟踪闭包/范围。您需要在那里使用async.forEach(Object.keys(trademarks), function(year, callback)....,并相应地调整异步控制流。

    当你有这个带有一个小包装函数的模式时,仅供参考:

    function convertPortfolio(trademarks, fn){
      async.waterfall([function(callback){
        groupByCountry(trademarks, callback)
      },
    

    您可以将async.apply 用于该样板:

    function convertPortfolio(trademarks, fn){
      async.waterfall([async.apply(groupByCountry, trademarks),
         ...
    

    【讨论】:

    • 谢谢!但是如果 Object.keys 是同步的,那么为什么它可以作为上面嵌套代码的一部分正常工作呢?我已经修改为使用 async.forEach,它与嵌套代码一起工作,但对 async.waterfall 又没有乐趣。是否需要采取额外的步骤(我认为这可能是您评论的一部分“相应地调整您的异步控制流)。也许原因是我对异步代码的真正含义有一个错误的理解——我认为当它比这更细微的时候,你只是抛出一个回调和它的异步......
    • 你在掩饰细节。我们正在谈论不同的sn-ps。上面的 async 和嵌套的 sn-ps(#1 和 #2)都没有使用 Object.keys(blah).forEach,这是一个同步的 forEach(不接受回调)。您正在制作基本的 async forEach 没有回调错误,这总是让人绊倒。
    • 我猜你混淆了 Object.keys(foo).forEach 采用 ITERATOR 函数和异步 I/O 函数采用 CALLBACK 函数这一事实。它们不是同一件事。迭代器定义要对序列中的每个项目执行的操作,回调会在异步操作完成时向调用者指示。
    • 抱歉,是的,我现在明白需要同时提供迭代器和回调函数作为 async.forEach 的一部分。再次感谢。
    猜你喜欢
    • 2019-05-15
    • 1970-01-01
    • 2011-01-22
    • 2021-12-03
    • 2020-06-23
    • 1970-01-01
    • 1970-01-01
    • 2015-12-31
    • 1970-01-01
    相关资源
    最近更新 更多