Array.forEach Callback at the end



我正在使用javascript的Array.forEach函数为列表中的每个元素获取不同的消息。所以我正在使用forEach函数,我正在寻找一个way来执行我的callback函数,cb(result)当foreach完成执行.forEachmsgAfterTimeout时。我读到有一种叫做promises的东西,但我真的不知道我如何在这里使用它们。

function msgAfterTimeout (who, timeout, onDone) {
setTimeout(function () {
onDone(" Hello " + who + "!");
}, timeout);
}
var test="";
var list = [{name:"foo",surname:"bar"},{name:"Jean",surname:"dupond"}];
function dispName(cb)
{
list.forEach(function(item, index)
{
msgAfterTimeout(item.name, 200, function (msg) 
{
test=msg+"n";
});
cb(result);
});
}
dispName(function(data){
console.log(data);
});

下面是你的 Promise 示例:

var list = [{name: "foo", surname: "bar"}, {name: "Jean", surname: "dupond"}];
function msgAfterTimeout(who, timeout) {
return new Promise(resolve =>
setTimeout(
() => resolve(" Hello " + who + "!"),
timeout)
);
}
Promise.all(
list.map(item => msgAfterTimeout(item.name, 200))
).then(
result => console.log(result.join('n'))
);

参考: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise

function msgAfterTimeout (who, timeout, onDone) {
setTimeout(function () {
onDone(" Hello " + who + "!");
}, timeout);
}
var test= "";
var list = [{name:"foo",surname:"bar"},{name:"Jean",surname:"dupond"}];
function newFunc(list, i, endCb) {
var name = list[i].name;
msgAfterTimeout(name, 200, function(msg) {
var test = msg + "n";
console.log(test);
if(i+1 == list.length) {
endCb();
}
else {
newFunc(list, i+1, endCb);
}
});
}
function dispName(cb)
{
newFunc(list, 0 , cb);    
}
dispName(function(){
console.log("Done with all!");
});

这输出:

你好福! 你好让! 全部完成!

forEach

串联处理事物,所以为了这个答案,让我们假设这是一个要求。Promise.all如@georg所示,它将并行处理这些项目——这是一个很好的答案,但如果一个系列是你真正需要的,它对你没有帮助。

Array.prototype 方法reducemapforEach是同步的,但您可以轻松地创建异步变体。您在这里使用forEach,但实际上是在手动执行reduce。因此,我们将从实现异步reducek开始,然后从那里开始

不要太担心理解reducek本身。您需要知道的是reducekreduce之间的主要区别在于,reduce函数接收一个额外的回调参数,该参数在每个项目完成时调用,并且reducek在整个输入列表完成时都有自己的回调。

function reducek (f, acc, [x, ...xs], k) {
if (x === undefined)
return k (acc)
else
return f (acc, x, y => reducek (f, y, xs, k))
}
function msgAfterTimeout (who, timeout, onDone) {
return setTimeout(onDone, timeout, "Hello " + who + "!")
}
function messageReducer (acc, item, done) {
return msgAfterTimeout(item.name, 200, function (text) {
return done([...acc, text])
})
}
function displayName (list, done) {
// use our async reduce here
return reducek (messageReducer, [], list, done)
}
var list = [{name:"foo",surname:"bar"},{name:"Jean",surname:"dupond"}]
displayName (list, function (texts) {
console.log("Done!", texts.join(' '))
})
// Done! Hello foo! Hello Jean!

需要注意的重要事项...

  1. 不再手动执行reduce,而不是使用状态为''(空字符串)初始化的test变量,reducek接受初始值作为参数。

  2. 在这里,我们使用初始状态[](空数组)来存储每个文本。完成后,我们使用texts.join(' ')将文本连接在一起。


不是另一个仪式...

所有这些都是很多仪式,延续不一定是异步流控制的最佳选择。事实上,Promise 被带到 JavaScript 是因为需要一个更好的工具。

// instead of returning a timeout, return a Promise
function msgAfterTimeout (who, timeout) {
return new Promise(function (resolve) {
setTimeout(resolve, timeout, "Hello " + who + "!")
})
}
// new async/await syntax - work with Promises in a most elegant fashion
// no more callback parameter; async implicitly returns a Promise
asyncfunction displayName (list) {
let texts = []
for (let item of list)
texts.push(awaitmsgAfterTimeout(item.name, 200))
return texts
}
var list = [{name:"foo",surname:"bar"},{name:"Jean",surname:"dupond"}]
// instead of a callback, chain a .then on the returned Promise
displayName(list).then(texts =>console.log("Done!", texts.join(' ')))
// Done! Hello foo! Hello Jean!

注意:如果您需要支持较旧的浏览器,则需要使用 Babel 之类的东西来转译async/await

相关内容

最新更新