Javascript 异步函数在一次调用而不是多次调用时工作

Javascript 异步函数在一次调用而不是多次调用时工作,javascript,node.js,async.js,Javascript,Node.js,Async.js,我已经使用async.瀑布来展开嵌套函数,如下所示 function convertPortfolio(trademarks, fn){ async.waterfall([function(callback){ groupByCountry(trademarks, callback) }, function(TMsGroupedByCountry, callback){ addEUTrademarks(TMsGroupedByCountry

我已经使用async.瀑布来展开嵌套函数,如下所示

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.瀑布示例中,目标对象是在返回数据可用之前记录的(因此我认为记录目标会导致空对象也就不足为奇了)

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

任何指导都将不胜感激

出于兴趣更新以下是使用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);
   });
}
Object.keys(商标).forEach
是同步的,不能正确跟踪闭包/作用域。您需要在那里使用
async.forEach(Object.keys(商标)、function(year、callback)…
,并相应地调整异步控制流

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

function convertPortfolio(trademarks, fn){
  async.waterfall([function(callback){
    groupByCountry(trademarks, callback)
  },
您可以使用
async。将
应用于该样板文件:

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

谢谢!但是如果Object.keys是同步的,那么为什么它可以作为上面嵌套代码的一部分很好地工作呢?我已经修改为使用async.forEach,它可以与嵌套代码一起工作,但是使用async.failter同样没有乐趣。是否需要采取额外的步骤(我认为这可能是您的注释“相应地调整异步控制流”的一部分)。可能原因是我对异步代码的理解有缺陷-我认为你只是在更微妙的时候加入了回调及其异步…你掩盖了细节。我们讨论的是不同的代码段。上面的异步或嵌套代码段(#1和#2)都没有使用
Object.keys(废话).forEach
这是一个同步的
forEach
(不接受回调)。您正在进行基本的异步forEach,没有回调错误,这会让人一直感到困惑。我猜您混淆了
Object.keys(foo)这一事实.forEach
接受一个迭代器函数,异步I/O函数接受一个回调函数。它们不是同一件事。迭代器定义对序列中的每个项执行的操作,回调在异步操作完成时向调用者指示。很抱歉,是的,我现在理解了提供这两个迭代器的必要性以及作为async.forEach的一部分的回调函数。再次感谢。