美文网首页
Promise在循环体中需要注意的一些事项

Promise在循环体中需要注意的一些事项

作者: 黑火巨雷 | 来源:发表于2018-03-27 21:00 被阅读111次

    我们首先知道,promise的then返回的始终是一个新promise。那么就存在下述情况

    let aPromise = new Promise((resolve,reject)=>{
        resolve('aPromise')
    })
    
    aPromise.then(res=>'bPromise')
    aPromise.then(res=>{console.log(res)}) // 实际上打印的是'aPromise'
    

    then不是改变aPromise的内容,而是始终返回新promise。

    如此,当我们要写一个循环体的时候。就需要一个游标来记录每次执行完的then。

    let delayPrint = (i = 1000) => {
        return new Promise((resolve, reject) => {
            setTimeout(() => {
                console.log(i);
                resolve('ok:'+i)
            }, 1000)
        })
    }
    
    let forbody = Promise.resolve('begin');
    for (let i = 1; i <= 5; i++) {
        forbody = forbody.then(res=>{
            return delayPrint(i);
        })
    }
    

    我们的forbody每次重新记录forbody.then返回的新promise。这样下次执行forbody.then的时候总能记录正确的位置。利用这一特性,我们可以制造循环体。上述代码可以依次打印1,2,3,4,5。需要注意的是如果把console.log(i)放入then中,变成console.log(res)会存在一个业务位置的问题。区别在于打印完5后立即结束,还是会再执行下一个而不打印。原因时i=5时执行完成后还会return一个delayPrint,相当于多执行了一次。虽然没有下次的then。

    也有一些比较丑陋的解决方案。如

    let forbody = Promise.resolve('begin');
    for (let i = 1; i <= 5; i++) {
        forbody = forbody.then(res=>{
            i!=5 && return delayPrint(i*1000);
        })
    }
    

    改良方案,用其他方式实现循环体

    面对定长的的循环体。可以用遍历数组 + Promise.all的方式来实现。
    使用这种方式很直观,并且在执行完成后能一次性得到所有的resolve

    相关文章

      网友评论

          本文标题:Promise在循环体中需要注意的一些事项

          本文链接:https://www.haomeiwen.com/subject/vpcnextx.html