资讯专栏INFORMATION COLUMN

Promise与遍历(循环,无穷多的then)遇到的问题及三个解决方案

freecode / 1803人阅读

摘要:今天碰到一个需要用做无穷循环的一个案例,顿时脑洞大开。事情是这样的,有这样的一群异步函数,将它们封装成,依次放入一个数组内需要让数组里的每一个依次进行,最后一个执行完就结束。

今天碰到一个需要用Promise做无穷循环then的一个案例,顿时脑洞大开。
事情是这样的,有这样的一群异步函数,

var func1 = function(callback){
    setTimeout(function(){
      console.log("foo");
      typeof(callback) !== "function" || callback();
    }, 499);
};

var func2 = function(callback){
    setTimeout(function(){
      console.log("bar");
      typeof(callback) !== "function" || callback();
    }, 500);
};

var func3 = function(callback){
    setTimeout(function(){
      console.log("foobar");
      typeof(callback) !== "function" || callback();
    }, 501);
};
// ... more ...

将它们封装成Promise,依次放入一个数组内:

// promisify those callback functions
var promisify = function(func){
  return function(){
    return new Promise(function(resolve){
      func(resolve);
    });
  }
}

// array can be infinitely long
var func_arr = [promisify(func1), promisify(func2), promisify(func3)];

需要让数组里的每一个Promise依次进行,最后一个执行完就结束。
我的第一个想法是这样的:

// solution 1 failed
var master = [];

for (var i = 0; i < func_arr.length; i++) {
  master[i] = function(){
    if (i == 0) {
      return func_arr[i]();
    }
    else {
      return master[i-1]().then(function(){
        return func_arr[i]();
      })
    }
  };
};

master[master.length-1]();

乍看没有问题啊,每一个新的master子函数的值是它上一个子函数的值加上一个then,但是一直报错——Maximum call stack size exceeded (node) / too much recursion (firefox)。
(12/24圣诞夜更新:已解决,修改了部分代码见下文)

僵了一会,还是谷哥帮助了我,搜到一个非常简洁的方法:

// solution 2 // success
func_arr.reduce(function(cur, next) {
    return cur.then(next);
}, Promise.resolve()).then(function() {
    console.log("job finished");
});

看得我腿都拍出坑了,其实是我想复杂了,没有必要在循环里不断地返回闭包函数等到最后调用,可以直接在循环里调用。
于是心有不甘,reduce()能实现的我大for岂有实现不了的道理,实则也不难,正确方法如下:

// solution 3 // success
var master = [];
master[0] = func_arr[0]();
for (var i = 1; i < func_arr.length; i++) {
  master[i] = master[i-1].then(func_arr[i]);
};

以下再提供一种重复调用函数式(就是递归)的方法:

// solution 4 // success
function loop(i) {
  if (i != func_arr.length) {
    return func_arr[i]()
    .then(function() {
      return loop(i+1);
    });
  }
  return Promise.resolve(i);
}

loop(0).then(function(loop_times){
  console.log("job finished");
});

不知道大家还有没有更好的解决方案,或者能告知我第一个方案出错的原因吧

================

12/24更新

感谢wowhy的提示,将我的solution 1的代码加入一层闭包,已经解决了因内外函数变量产生的BUG:

// solution 1 // success now
var master = [];

for (var i = 0; i < func_arr.length; i++) {
  master[i] = (function(j){
    return function(){
      if (j == 0) {
        return func_arr[j]();
      }
      else {
        return master[j-1]().then(function(){
          return func_arr[j]();
        })
      }
    }
  })(i);
};

var execute = master[master.length-1];
execute();

乍看这一串代码很长,对比之前的方案显得完全多余,在我看来,可以生成在外部其他的上下文内进行独立调用的函数要更符合我大脑的思维方式:)。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/78354.html

相关文章

  • 【译】前端知识储备——Promise/A+规范

    摘要:在将来的其他规范中可能会涉及这些没有提及的内容。它禁止被触发多次。如果到了状态,那么所有的回调函数都必须按照他们原有的顺序进行调用执行。 概述 自从准备晋级之后,就拖更了很久了,既然晋级弄完了,那么也恢复更新了。 在面试别人的过程中,发现基本上没有人对整个Promise完全了解,因此希望通过这篇文章来帮助大家了解下Promise的全貌。本文的主要内容是Promise/A+规范的译文,主...

    Gemini 评论0 收藏0
  • Generator:JS执行权真实操作者

    摘要:执行权由此单向稳定的在不同函数中切换。调用函数后,引擎会为其开辟一个独立的函数执行栈以下简称栈。执行权再次回到外部。成功执行完函数,则改变的状态为成功。执行函数返回的遍历器对象会继承函数的原型对象。遇到下一个断点,交出执行权传出返回值。 前言 ES6提供了一种新型的异步编程解决方案:Generator函数(以下简称G函数)。它不是使用JS现有能力按照一定标准制定出来的东西(Promis...

    YanceyOfficial 评论0 收藏0
  • 我了解到JavaScript异步编程

    摘要:接下来我们看下三类异步编程的实现。事件监听事件发布订阅事件监听是一种非常常见的异步编程模式,它是一种典型的逻辑分离方式,对代码解耦很有用处。 一、 一道面试题 前段时间面试,考察比较多的是js异步编程方面的相关知识点,如今,正好轮到自己分享技术,所以想把js异步编程学习下,做个总结。下面这个demo 概括了大多数面试过程中遇到的问题: for(var i = 0; i < 3; i++...

    RichardXG 评论0 收藏0
  • 前端JS代码规范

    摘要:缩进为个空格句末必须用分号结尾待定就无分号注释单行注释多行注释代码注释和再提交重要函数或者类等都要添加头描述字符串拼接应使用数组保存字符串片段,使用时调用方法。 前言 下面这几点将工作中所踩的一些坑简单整理了一下,团队几个人开发,一些默契就比较重要,可以提高开发效率和代码的可读性 命名,编码和注释 命名 A.文件夹命名:文件夹、文件的命名与命名空间应能代表代码功能,可读性强,如hubB...

    zhiwei 评论0 收藏0
  • Javascript关于异步编程发展

    摘要:前言转简体重新排版布局代码全面使用并且直接附上输出结果补充细节补充内容增加例子说明新增和在遍历情况下怎么使用上文讲了关于执行机制单线程同异步任务事件循环的知识点我们知道在某一时刻内只能执行特定的一个任务并且会阻塞其它任务执行为了解决这个 前言 PS:2018/08/08 转简体2018/08/09 重新排版布局,代码全面使用ES6并且直接附上输出结果,补充细节2018/08/13 补充...

    princekin 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<