正如标题所示。我怎么做呢?

我想在foreach循环遍历每个元素并完成一些异步处理后调用whenAllDone()。

[1, 2, 3].forEach(
  function(item, index, array, done) {
     asyncFunction(item, function itemDone() {
       console.log(item + " done");
       done();
     });
  }, function allDone() {
     console.log("All done");
     whenAllDone();
  }
);

有可能让它这样工作吗?当forEach的第二个参数是一个回调函数,当它经过所有迭代时运行?

预期的输出:

3 done
1 done
2 done
All done!

当前回答

在这个帖子中有许多解决方案和方法来实现这一点!

但是,如果你需要用map和async/await来做这个,那么这里就是

// Execution Starts
console.log("start")

// The Map will return promises
// the Execution will not go forward until all the promises are resolved.
await Promise.all(
    [1, 2, 3].map( async (item) => {
        await asyncFunction(item)
    })
)

// Will only run after all the items have resolved the asynchronous function. 
console.log("End")

输出将如下所示!可能根据异步函数而有所不同。

start
2
3
1
end

注意:如果你在map中使用await,它总是会返回promises数组。

其他回答

你不应该需要一个回调来迭代一个列表。只需在循环之后添加end()调用。

posts.forEach(function(v, i){
   res.write(v + ". Index " + i);
});
res.end();

在ES2018中,你可以使用异步迭代器:

const asyncFunction = a => fetch(a);
const itemDone = a => console.log(a);

async function example() {
  const arrayOfFetchPromises = [1, 2, 3].map(asyncFunction);

  for await (const item of arrayOfFetchPromises) {
    itemDone(item);
  }

  console.log('All done');
}

如果使用setInterval来检查完整的迭代计数,会带来保证。虽然不确定它是否不会超载范围,但我使用它,似乎是一个

_.forEach(actual_JSON, function (key, value) {

     // run any action and push with each iteration 

     array.push(response.id)

});


setInterval(function(){

    if(array.length > 300) {

        callback()

    }

}, 100);
//First Example
save() {
    this.holdImageData.forEach((val,i) => {
        this.UploadToMinio(val.file, val.index, res => {
            if (res && i+1 == this.holdImageData.length) {
                this.FinallySave();
            }
        })
    })
}

UploadToMinio(files, index, callback) {
    this._fileUploadService.uploadFile(files[0], files[0].name, 'rms').subscribe(data => {
        if (data) {
            console.log('data >>> ', data);
            callback(true);
        }
    })
}

FinallySave() {}

//Second Example
var sum = 0; // It can be global variable
startFunction() {
    this.sumFunction(2, 4, res => {
        if (res == true && sum == 6) {
            this.saveFunction();
        } else {
            //call to another function
        }
    })
}

sumFunction(num1, num2, callback) {
    if ((num1 + num2) == 6) {
        callback(true)
    }
    callback(false);
}

数组中。forEach并没有提供这样的细节(如果可以的话),但是有几种方法可以实现你想要的:

使用一个简单的计数器

function callback () { console.log('all done'); }

var itemsProcessed = 0;

[1, 2, 3].forEach((item, index, array) => {
  asyncFunction(item, () => {
    itemsProcessed++;
    if(itemsProcessed === array.length) {
      callback();
    }
  });
});

这种方法保证在调用"done"回调之前处理所有项。您需要使用一个在回调中更新的计数器。依赖于索引参数的值并不能提供相同的保证,因为异步操作的返回顺序是不能保证的。

使用ES6承诺

(一个承诺库可以用于较旧的浏览器):

Process all requests guaranteeing synchronous execution (e.g. 1 then 2 then 3) function asyncFunction (item, cb) { setTimeout(() => { console.log('done with', item); cb(); }, 100); } let requests = [1, 2, 3].reduce((promiseChain, item) => { return promiseChain.then(() => new Promise((resolve) => { asyncFunction(item, resolve); })); }, Promise.resolve()); requests.then(() => console.log('done')) Process all async requests without "synchronous" execution (2 may finish faster than 1) let requests = [1,2,3].map((item) => { return new Promise((resolve) => { asyncFunction(item, resolve); }); }) Promise.all(requests).then(() => console.log('done'));

使用异步库

还有其他异步库,async是最流行的,它们提供了表达所需内容的机制。

Edit

问题的主体已被编辑以删除之前的同步示例代码,因此我更新了我的答案以澄清。 最初的例子使用了类似于同步的代码来模拟异步行为,因此应用了以下内容:

数组中。forEach是同步的,res.write也是同步的,所以你可以简单地把你的回调放在你调用forEach之后:

  posts.foreach(function(v, i) {
    res.write(v + ". index " + i);
  });

  res.end();