.forEach 完成后执行回调函数

Posted

技术标签:

【中文标题】.forEach 完成后执行回调函数【英文标题】:Executing a callback function after .forEach finishes 【发布时间】:2018-10-30 00:49:25 【问题描述】:

我正在尝试在 forEach 循环完成所有迭代后执行一个函数。

这个answer 提供了一个有趣的解决方案,但我无法让它工作。

这是我改编的代码,创建了一个简单的 asyncFunction()。

function callback ()  console.log('all done'); 
function asyncFunction(item) 
  console.log("in async function, item is " + item)

var itemsProcessed = 0;

[1, 2, 3].forEach((item, index, array) => 
  asyncFunction(item, () => 
    itemsProcessed++;
    console.log("in callback area, itemsProcessed is " + itemsProcessed )
    if(itemsProcessed === array.length) 
      callback();
    
  );
);

正如在此JSfiddle 中可见,脚本正确执行异步函数,但未能输入递增itemsProcessed 并应触发callback() 函数的部分。

我对胖箭头函数不太熟悉,所以错误可能来自它们的使用。

谁能解释为什么脚本没有按预期运行?

【问题讨论】:

当你调用它时,你将一个函数作为第二个参数传递给asyncFunction(),但函数声明不期望第二个参数,并且永远不会调用传递给它的回调 有道理,谢谢。但是我不确定要声明哪个参数。显然asyncFunction(item, ()) 不起作用。您能否更明确地解释如何处理第二个论点? 【参考方案1】:

在这种情况下,更现代的方法是使用 Promise

function asyncFunction(item) 
   // return a promise
  return new Promise((resolve, reject) => 
    setTimeout(() => 
      console.log("in async function, item is " + item)
      // resolve promise when data is ready
      resolve(item)
    , Math.random()*2000)// random delay to stagger order of returns

  )



// create array of promises
let promiseArray = [1, 2, 3].map(asyncFunction);

// runs when all promises are resolved
Promise.all(promiseArray).then(results => 
  console.log('all done')
  // results array will be in same order as original array
  console.log('results are: ', results)
)
.as-console-wrapper max-height: 100%!important;top:0

【讨论】:

先生。查理,非常感谢!我从这个 sn-p 中学习并继续我的任务。在这个我们不能见面和握手的虚拟世界里。愿你得到我的善报。【参考方案2】:

因为您想将回调函数作为第二个参数传递给asyncFunction,您需要指定将有一个回调函数作为第二个参数,并且您需要这样调用:

function asyncFunction(item, cb) 
  console.log("in async function, item is " + item)
  cb()

此外,您的代码可以重写,以便更容易理解回调函数的使用。你的代码:

[1, 2, 3].forEach((item, index, array) => 
  asyncFunction(item, () => 
    itemsProcessed++;
    console.log("in callback area, itemsProcessed is " + itemsProcessed )
    if(itemsProcessed === array.length) 
      callback();
    
  );
);

等同于:

[1, 2, 3].forEach((item, index, array) => 
  function cbFunc() 
    itemsProcessed++;
    console.log("in callback area, itemsProcessed is " + itemsProcessed )
    if(itemsProcessed === array.length) 
      callback();
    
  
  asyncFunction(item, cbFunc);
);

【讨论】:

【参考方案3】:

将每个元素映射到一个 Promise,然后使用 Promise.all()

Promise.all([1, 2, 3].map(async num => num));

当然,如果你愿意,你可以在异步函数内部做一些更复杂的事情。

Promise.all([1, 2, 3].map(num => 

    return new Promise((reject, resolve) =>
    
        setTimeout(() => resolve(num), 5000);
    )
));

如果您正在执行的代码是同步的或涉及超时,则使用Promise 构造函数而不是异步函数。

【讨论】:

以上是关于.forEach 完成后执行回调函数的主要内容,如果未能解决你的问题,请参考以下文章

promise核心技术 2.两种回调函数 js中error的处理

回调函数

同步回调函数与异步回调函数

如何在 CPU 内核上执行函数,并在完成后获得回调?

jQuery mmenu 插件完成激活后是不是有回调或任何其他方式来执行函数?

Node.js 回调函数