欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

ES6中的Promise对象

程序员文章站 2022-07-03 09:33:44
...

什么是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

上一篇: promise 使用

下一篇: Promise使用