简体   繁体   English

最后的Array.forEach回调

[英]Array.forEach Callback at the end

I'm using Array.forEach function of javascript to get a different message for each element of a list. 我正在使用javascript的Array.forEach函数为列表的每个元素获取不同的消息。 So I'm using forEach function and I'm looking for a way to execute my callback function cb(result) when the foreach as finished to both execute .forEach and msgAfterTimeout . 所以我正在使用forEach函数,并且正在寻找一种way来在foreach完成时执行.forEachmsgAfterTimeout时执行我的callback函数cb(result) I read that there was something called promises but I don't really get how I can use them here. 我读到有些东西叫做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!");
});

This outputs: 输出:

Hello foo! 你好,富! Hello Jean! 你好,简! Done with all! 完成所有!

Here's your example with Promises: 这是您的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')) ); 

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

forEach processes things in series , so for the sake of this answer, let's assume that's a requirement. forEach系列处理的事情,所以对于这个答案起见,我们假设这是一个必要条件。 Promise.all as demonstrated by @georg will process the items in parallel – it's a good answer but it won't help you if a series is what you actually need. Promise.all演示的Promise.all将并行处理这些项目–这是一个很好的答案,但是如果您确实需要一系列,它将无法为您提供帮助。

The Array.prototype methods reduce , map , and forEach are synchronous, but you could easily make an asynchronous variants. Array.prototype方法reducemapforEach是同步的,但是您可以轻松地创建异步变量。 You're using forEach here but you're actually performing a reduce by hand. 您在这里使用forEach ,但实际上是在手动执行reduce So we'll start by implementing an asynchronous reducek and then go from there 因此,我们将从实现异步reducek ,然后从那里开始

Don't worry too much about understanding reducek itself. 不必太担心了解reducek本身。 All you need to know is the primary difference between reducek and reduce is that the reducing function receives an extra callback argument that is called when each item is done, and reducek has its own callback for when the entire input list is done. 您需要知道的是reducekreduce之间的主要区别是reducek函数会收到一个额外的回调参数,该参数在每个项目完成时都会被调用,而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! 

Important things to notice ... 重要注意事项...

  1. No longer performing reduce by hand – instead of using a test variable initialized with state of '' (empty string), reducek accepts the initial value as an argument. reducek不再手动执行reduce –代替使用状态为'' (空字符串)初始化的test变量, reducek接受初始值作为参数。

  2. Here we're using an initial state of of [] (empty array) to store each of the texts. 在这里,我们使用初始状态为[] (空数组)来存储每个文本。 When we're done, we join the texts together using texts.join(' ') . 完成后,我们使用texts.join(' ')将文本连接在一起。


Not Another Ceremony ... 没有其他仪式...

All of that is a lot of ceremony and continuations are not necessarily the best for asynchronous flow control. 所有这些都是很多仪式,并且延续不一定是异步流控制的最佳方法。 In fact, Promises were brought to JavaScript because a better tool was needed. 实际上,将Promises引入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
async function displayName (list) {
  let texts = []
  for (let item of list)
    texts.push(await 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!

Note: If you need to support older browsers, async / await needs to be transpiled using something like Babel. 注意:如果您需要支持旧版浏览器,则需要使用Babel这样的东西来对async / await进行转译。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM