V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐关注
Meteor
JSLint - a JavaScript code quality tool
jsFiddle
D3.js
WebStorm
推荐书目
JavaScript 权威指南第 5 版
Closure: The Definitive Guide
abcbuzhiming
V2EX  ›  JavaScript

求教,如何使用 promise 完成循环状态下的链式异步任务

  •  
  •   abcbuzhiming · 2017-04-07 17:59:15 +08:00 · 6628 次点击
    这是一个创建于 2785 天前的主题,其中的信息可能已经有所发展或是发生改变。
    Promise 能像下面这样顺序完成链式异步任务

    promise1().then(function(data) {
    console.log(data);
    return promise2();
    })
    .then(function(data) {
    console.log(data);
    return promise3();
    })
    .then(function(data) {
    console.log(data);
    return '结束了吧'
    }).then(function(data) {
    console.log(data);
    });
    }
    但是这里存在一个问题, promise2 和 promise3 都必须是在外部预定义好的。

    但是现在我有这么一个需求,我可能有一大批 promise 对象,这些 promise 对象都是按一定算法用循环生成的。结果这就遇到了坑,我试图这么干

    function axiosLoop(index) {
    /*
    XXXXXX
    */
    return axiosObj;
    }
    var objTemp = null;
    for (var i = 0; i < 10; i++) {
    objTemp = axiosLoop(i).then(function (data) {
    console.log(data);
    return axiosLoop(i+1); //这么干是不行的,因为这个 i 值是引用外部的 i ,它会直接演变成最大的 10
    }).catch(function (error) {
    console.log(error);
    });
    }

    =========
    我该怎么解决这个问题,这个问题不能使用类似 promis.all()来执行,因为我一定要保证有序执行
    13 条回复    2017-04-09 14:31:53 +08:00
    freeminder
        1
    freeminder  
       2017-04-07 18:24:12 +08:00
    再包一层
    objTemp = axiosLoop(i).then((function (idx){
    return function(data){
    console.log(data);
    return axiosLoop(idx);
    }
    })(i+1)).catch(function (error) {
    console.log(error);
    });
    nino
        2
    nino  
       2017-04-07 18:43:50 +08:00
    AlisaDestiny
        3
    AlisaDestiny  
       2017-04-07 18:56:27 +08:00
    @freeminder 跟我第一感一样。用闭包。
    bdbai
        4
    bdbai  
       2017-04-07 21:52:20 +08:00 via Android
    支持 ES6 的话,把 for 里面的 var 改成 let 。
    hythyt9898
        5
    hythyt9898  
       2017-04-07 22:06:32 +08:00 via iPhone
    为何不用 async/await ?
    ck65
        6
    ck65  
       2017-04-07 23:19:01 +08:00 via iPhone
    比较脏难维护和扩展,但能解燃眉之急的方案:引 deasync 包,把请求封装成一个同步方法。
    需要额外学习、要求特定 nodejs 版本或使用编译工具,但优雅稳定的方案: async/await 。
    abcbuzhiming
        7
    abcbuzhiming  
    OP
       2017-04-07 23:30:40 +08:00
    @freeminder
    @AlisaDestiny
    @ck65
    谢谢楼上各位,奋斗了一晚上,终于在重新理解 promise 模型和闭包变量作用域的基础上,按照 freeminder 的方法搞定了。折腾死了,我终于明白为啥 Promise 仅仅出来了两年就被 async/await 干掉了, 12 万分的希望 async/await 早日在前端普及吧,再也不想拿 Promise 写东西了
    imdoge
        9
    imdoge  
       2017-04-08 01:34:52 +08:00
    可以用 reduce 来, arr.reduce((promise, item) => { return promise.then(() => asyncReq(item)), asyncReq1()}
    xieranmaya
        10
    xieranmaya  
       2017-04-08 12:31:57 +08:00
    [p1,p2,p3].reduce((seq,next) => seq.then(value=>next()), Promise.resolve())

    说白了有点像 x = x + n
    你看啊: seq = seq.then(value => task(value)
    是不是很像
    bdbai
        11
    bdbai  
       2017-04-08 22:00:58 +08:00 via Android
    @abcbuzhiming Promise 活的好好的,没被干掉吧。
    嫌原生 Promise 不好用可以试试 bluebird 。
    xieranmaya
        12
    xieranmaya  
       2017-04-09 12:49:30 +08:00
    @abcbuzhiming
    @bdbai 说的很对, Promise 并没有“被” async/await 干掉,相反, async/await 是基于 Promise 的,如果你不深入理解 Promise ,你也不会真正理解 async/await ,事实上, async 函数的调用就是返回 Promise ,而 await 操作符后面必须是一个 Promise 对象,这意味着你要用 async/await 的时候,必须还是要自己实现一些返回 Promise 的函数
    LeoEatle
        13
    LeoEatle  
       2017-04-09 14:31:53 +08:00 via iPhone
    最简单的处理方案就是,用 let
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   1256 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 23ms · UTC 23:29 · PVG 07:29 · LAX 15:29 · JFK 18:29
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.