美文网首页
ES6中的Promise对象

ES6中的Promise对象

作者: Gopal | 来源:发表于2018-07-17 18:46 被阅读34次

    什么是Promise对象?

    Promise是异步编程的一种解决方案,比起传统的解决方案(回调函数和事件),它显得更加的强大和方便(具体请看下文)。从语法上来讲,Promise是一个对象,从它可以获取异步操作的消息。Promise对象提供统一的API,各种异步操作都可以用同样的方法进行处理。

    Promise有什么用?

    大家一致会回答,回调地狱。那什么又是回调地狱?它有什么缺点?

    如果要执行四个步骤,依次执行,那么传统我们可能会这么做:

    step1(function (value1) {
        step2(value1, function(value2) {
            step3(value2, function(value3) {
                step4(value3, function(value4) {
                    // Do something with value4
                });
            });
        });
    });
    

    为了解决这种看起来不很舒服,写起来更不舒服的写法,我们可能会想起链式写法:

    var obj = {
        stepOne: function () {
            console.log('one');
            return this;
        },
        stepTwo: function () {
            console.log('two');
            return this;
        },
        stepThree: function () {
            console.log('three');
            return this;
        }
    }
    
    obj.stepOne().stepThree().stepTwo();
    

    这种写法的核心在于,每次都返回this。
    这样的好处在于:

    • 每一个操作都是独立的一个函数
    • 可以组装,也就是我们可以控制执行的流程

    那如果我们还需要一些其他需求的时候呢?比如:

    • 如果上一步的结果作为下一步的输入就更好了
    • 如果出错我能够捕捉就更好了
    • 如果我在函数中能够控制流程就好了
      ....

    这个时候,就需要用到我们强大的Promise了

    基础用法

    先来看看怎么使用吧!直接上代码:

    const p1 = new Promise(function(resolve, reject) {
        // 在这里做一些逻辑处理
        // 如果异步操作成功的时候,调用resolve
        if (true) {
            resolve('success');
        } else {
            // 操作失败后我们就调用reject()
            reject('fail');
        }
    })
    
    p1.then((val) => {
        console.log(val); // success
    }, (err) => {
        console.log(err)
    })
    

    我们可以看到Promise是一个构造函数,用来生成Promise实例,它接收一个函数作为参数,这个函数有两个参数——resolve和reject(它们也是两个函数,已经由JavaScript引擎提供,不用自己部署)。

    我们经常会在这个函数里处理一些逻辑,如果处理成功后我们会执行resolve(将状态从“未完成”转为“完成”),失败后执行reject(将状态从“未完成”转换为“失败”)。

    三个状态

    • pedding(未完成)
    • resolved(完成)
    • rejected(失败)

    实例生成之后,我们可以使用then方法指定resolved和rejected状态的回调函数。像上面的代码,就相当于执行第一个回调函数,第二个不会执行(这个时候其实不提供第二个参数也是可以的)。

    如果是执行失败,状态变成reject的时候,就会执行第二个回调函数,就会输出'fail'。但是其实我们不是很推荐这样的写法,我们可以将第二个回调函数写catch方法的形式。

    const p1 = new Promise(function(resolve, reject) {
        // 在这里做一些逻辑处理
        // 如果异步操作成功的时候,调用resolve
        if (false) {
            resolve('success');
        } else {
            // 操作失败后我们就调用reject()
            reject('fail');
        }
    })
    
    p1.then((val) => {
        console.log(val);
    }).catch((err) => {
        console.log(err); // fail
    })
    

    这种写法类似于try...catch...,更加易于我们理解。这个时候我们其实就已经解决了出错我们能够捕捉的问题了。

    控制代码的执行顺序

    采用链式的then,可以指定一组按照次序调用的回调函数。这个时候前面的一个返回的可能是另外一个Promise对象(也就是说有异步操作)。这样后面的这个Promise就依赖于前面Promise对象的状态。

    const p1 = new Promise(function(resolve, reject) {
        console.log(1);
        setTimeout(function() {
            console.log(2);
            resolve();
        }, 1000);
    })
    
    const p2 = new Promise(function(resolve, reject) {
        console.log(3);
        resolve(p1);
    })
    
    p2.then(() => {
        console.log(4);
    }).then(() => {
        console.log(5);
    })
    
    输出结果

    以上代码,我们应该注意一点p2的resolve方法将p1作为参数,也就是说p2的执行依赖于p1的执行。当p2准备好的时候,p1可能还没准备好,这个时候p2就得等p1。

    另外,需要注意的一点就是,then方法返回的是一个新的Promise实例(注意,不是之前的Promise实例),因此可以采用链式写法,即then方法之后再调用另一个then方法。这样,我们就可以实现了上面的需求了!

    Promise的几个重要方法

    下面简单介绍一下Promise对象的几个方法,我们经常也会用到。

    Promise.all()
    直接上代码:

    const p = Promise.all([p1, p2, p3]);
    

    Promise.all方法接收一个数组作为参数,p1、p2、p3都是Promise实例。这个时候p的状态由p1、p2、p3。它们的依赖机制类似于电路中的串联,现在我们使用三条线(就是p1、p2、p3)进行串联,p就是最后灯泡,灯泡要亮的话,三个都要成功,只要其中的一个没有成功,那么p的状态就是rejected。

    Promise.race()

    const p = Promise.race([p1, p2, p3]);
    

    这个方法也是接受一个数组作为参数。race的英文意思就有竞赛的意思。上面的代码中表示,p1、p2、p3中哪个胜出(最新状态发生改变,不管是失败还是成功),那么p的状态就会跟着它改变。

    Promise.resolve()
    作用:将现有对象转换成Promise对象,这样我们就可以调用then方法等

    const jsPromise = Promise.resolve($.ajax('/whatever.json'));
    

    Promise.reject()

    Promise.reject(reason)方法也会返回一个Promise实例,该实例状态为rejected。

    const p = Promise.reject('出错了');
    // 等同于
    const p = new Promise((resolve, reject) => reject('出错了'))
    
    p.then(null, function (s) {
      console.log(s)
    });
    // 出错了
    

    参考:
    https://cnodejs.org/topic/560dbc826a1ed28204a1e7de

    http://es6.ruanyifeng.com/#docs/promise

    相关文章

      网友评论

          本文标题:ES6中的Promise对象

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