Array.forEach结束回调

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);
});
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!");
});

这输出:

Hello foo! Hello Jean! Done with all!

这是你的 Promises 示例:

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

forEach 处理 系列 中的内容,因此为了这个答案,让我们假设这是一项要求。 Promise.all 正如@georg 所展示的那样,它将处理 并行 中的项目——这是一个很好的答案,但如果系列是你真正需要的,它不会帮助你。

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

不要太担心了解 reducek 本身。您需要知道的是 reducekreduce 之间的主要区别在于,reducing 函数接收一个额外的回调参数,该参数在每个项目完成时调用,而 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(' ').

  3. 将文本连接在一起

不是另一个仪式...

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

// 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
<b>async</b> function displayName (list) {
  let texts = []
  for (let item of list)
    texts.push(<b>await</b> msgAfterTimeout(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!

注意:如果您需要支持旧版浏览器,async/await 需要使用 Babel 之类的工具进行转译。