探究promise

作者: 俊滔_b059 | 来源:发表于2018-04-19 15:22 被阅读24次
    前言

    大家都知道Promise是ES6的一个针对回调地狱的一种解决方案,我们可以用promise去封装异步请求,用链式写法去处理复杂的业务情景,但是在一些细节问题上很容易犯一些错误

    场景1:两个或N个异步请求相互依赖嵌套

    如:用户页面需要进行两个请求:[请求获取用户信息],[通过这个用户的id去请求用户个人消费记录]

    //用settimeout来模拟异步耗时请求
    function getUser(){
        return new Promise((resolve, reject) => {
            setTimeout(function(){
                resolve({'id':1,'name':'cjt','age':24})
            },1000)
        })
    }
    
    function getRecord(id){
        return new Promise((resolve, reject) => {
            setTimeout(function(){
                let res = '用户id:'+id+"的记录为5条"
                resolve(res)
            },1000)
        })
    }
    

    OK,现在两个请求的异步操作我们封装好了,几种实现方式是:

    //不好的方式
    getUser().then(user => {
        let id = user.id;
        getRecord(id).then(res => {
            console.log(res)
        })
    })
    //运行结果 用户id:1的记录为5条
    
    //更好的写法
    getUser().then(user => {
        let id = user.id;
        return getRecord(id)
    }).then(res => {
        console.log(res)
    })
    //运行结果 用户id:1的记录为5条
    

    好的,解决这个问题后,如果特殊业务情况下,我想在第二个then方法中,调用第一个then的user,直接调用会报错undefined
    不过按照不好的那种方式处理是可以取到user对象的,但是逻辑和嵌套多了,代码又变成了金字塔型, 无限的向右侧移动,所以这种情况的解决办法是 抛弃陈见,拥抱金字塔,但是在第一种写法的基础上,我们稍作修改

    function needBoth(user,record){
        let result = 'user:'+user+',record:'+record
        return Promise.resolve(result);
    }
    
    function step1(user){
        let id = user.id;
        return getRecord(id).then(record => {
            return needBoth(user,record); //需要前两个异步结果的方法
        })
    }
    
    getUser()
       .then(step1)
       .then(result => {
          console.log(result)
       })  
    //user:[object Object],record:用户id:1的记录为5条
    

    由于你的 promise 代码开始变得更加复杂,你可能发现自己开始将越来越多的函数抽离到命名函数中,我发现这样做,你的代码会越来越漂亮,就像这样

    putYourRightFootIn()
      .then(putYourRightFootOut)
      .then(putYourRightFootIn)  
      .then(shakeItAllAbout);
    

    这就是 promises 的重点。

    场景2:等N个异步请求都成功后,再执行之后的操作

    遇到这种场景我们可以使用Promise.all(), 比如下面这个文章
    80%面试者都不及格的JS题

    很经典的一个JS面试题

    for (var i = 0; i < 5; i++) { 
            setTimeout(function() {
                console.log(new Date, i);
            }, 1000); 
    }
    console.log(new Date, i);
    //结果:
    //Thu Apr 19 2018 14:51:51 GMT+0800 (中国标准时间) 5
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 5
    

    原理很简单,异步事件进入task queue,先执行了for循环之后的console

    for (var i = 0; i < 5; i++) {
        (function(i){ 
            setTimeout(function() {
                console.log(new Date, i);
            }, 1000); 
        }(i))
    }
    console.log(new Date, i);
    //结果:
    //Thu Apr 19 2018 14:51:52 GMT+0800 (中国标准时间) 5
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 0
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 1
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 2
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 3
    //Thu Apr 19 2018 14:51:53 GMT+0800 (中国标准时间) 4
    
    //注意: 这里用let不行,因为let的作用于被限制到for循环中了,外部调用会报错
    

    如果我想让他输出0,1,2,3,4,5或者0->1->2->3->4->5呢?
    注:0,1,2...表示同时输出,0->1->2...表示每次都间隔1秒

    //0->1->2->3->4->5
    let task = [];  //promise对象数组
    for (var i = 0; i < 5; i++) {
        (function(j){ 
            task.push(new Promise((resolve) => {
                setTimeout(function() {
                    console.log(new Date, j);
                    resolve();
                }, 1000 * j); 
            })); 
        }(i))
    }
    Promise.all(task).then(results => {
        setTimeout(function(){
            console.log(new Date, i);
        },1000)
    })
    
    结果
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 0
    Thu Apr 19 2018 15:14:03 GMT+0800 (中国标准时间) 1
    Thu Apr 19 2018 15:14:04 GMT+0800 (中国标准时间) 2
    Thu Apr 19 2018 15:14:05 GMT+0800 (中国标准时间) 3
    Thu Apr 19 2018 15:14:06 GMT+0800 (中国标准时间) 4
    Thu Apr 19 2018 15:14:08 GMT+0800 (中国标准时间) 5
    
    
    
    //0,1,2,3,4,5
    let task = [];  //promise对象数组
    for (var i = 0; i < 5; i++) {
        (function(j){ 
            task.push(new Promise((resolve) => {
                setTimeout(function() {
                    console.log(new Date, j);
                    resolve();
                }, 1000); 
            })); 
        }(i))
    }
    Promise.all(task).then(results => {
        console.log(new Date, i);
    })
    
    结果
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 0
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 1
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 2
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 3
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 4
    Thu Apr 19 2018 15:14:02 GMT+0800 (中国标准时间) 5
    

    相关文章

      网友评论

        本文标题:探究promise

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