Skip to content

Promise

Promise 是异步编程的一种解决方案。简单的说就是一个容器,里面保存着一个异步操作的结果。 Promise 是一个对象,他可以获取异步操作的消息。有以下特点:

  • 对象的状态不受外界影响,Promise 对象代表一个异步操作,有三种状态:pending(仅限进行中),fulfilled(已成功),rejected(已失败)。
  • 一旦状态改变就不会再变,任何时候都可以得到这个结果。状态改变只能是从 pending 到 fulfilled 和 pending 到 rejected。

缺点:

  • 一旦新建就无法取消
  • 如果不设置回调函数 Promise 内部抛出的错误不会反应到外部
  • 当处于 pending 状态是无法知道进展到哪一个阶段

基本用法

Promise 对象是一个构造函数,用来生成 Promise 实例

var promise = new Promise(function(resolve, reject) {
    // ... some code
    if (/* 异步操作成功 */){
        resolve(value);
    } else {
        reject(error);
    }
});

promise.then(function(value) {
    // success
}, function(error) {
    // failure
});

Promise 构造函数接受一个函数作为参数,该函数有两个参数 resolve 和 reject。resolve 函数的作用是将 Promise 对象的状态从 pending 变为 resolved,在异步操作成功的时候将结果传递出去。 reject 函数的作用是将 Promise 对象的状态从 pending 变为 rejected,在失败时调用并将结果作为参数传递出去。 Promise 实例生效后可以用 then 方法分别指定 resolved 的状态和 rejected 状态的回调函数。

Promise.prototype.then()

then 方法是定义在原型对象 Promise.prototype 上的。它的作用是为 Promise 实例添加状态改变时的回调函数。then 方法返回的是一个新的 Promise 实例,因此可是采用链式的写法,即在 then 后再加拎一个 then 方法

Promise.prototype.catch()

Promise.prototype.catch 方法是.then(null, rejection)的别名,用于指定发生错误时的回调。如果 then 方法指定的回调函数运行中抛出异常也会被 catch 方法捕获。 如果 Promise 状态已经变成 resolved,再抛出错误是无效的。

Promise.all()

将多个 Promise 实例包装成一个新的 Promise 实例

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

Promise.all 方法接受一个数组作为参数(可以不是数组但必须具有 Iterator 接口),每个元素都是 Promise 实例,如果不是会调用 Promise.resolve 方法,将参数转为 Promise 实例 p 的状态由 p1, p2, p3 决定:

  • 只有 p1, p2, p3 状态都变为 fulfilled,p 的状态才会变为 fulfilled,此时 p1, p2, p3 的返回值组成一个数组传递给回调函数
  • 只要 p1, p2, p3 之中一个被 rejected,p 的状态就变为 rejected,此时第一个被 reject 的实例的返回值会传给 p 的回调函数

Promise.race()

同样是将多个 Promise 实例包装成一个新的 Promise 实例。不同的是只要有一个先改变状态,新 Promise 的状态就会跟着改变。

Promise.resolve()

将现有的对象转为 Promise 对象

Promise.reject()

返回一个新的 Promise 实例,状态为 rejected

两个有用的附加方法

ES6 的 Promise API 提供的方法不是很多,有些有用的方法可以自己部署。下面介 绍如何部署两个不在 ES6 之中、但很有用的方法。

  • done()

    Promise 对象的回调链不管以 then 结尾还是 catch 结尾,只要最后一个方法抛出异常都可能无法捕捉。因此提供一个 done 方法总是处于回调的尾端保证抛出任何可能的错误。

Promise.prototype.done = function (onFulfilled, onRejected) {
    this.then(onFulfilled, onRejected)
        .catch(function (reason) {
            // 抛出一个全局错误
            setTimeout(() => { throw reason }, 0);
    });
};
  • finally()

    不管 Promise 对象最后的状态如何都会执行。

Promise.prototype.finally = function (callback) {
    let P = this.constructor;
    return this.then(
        value => P.resolve(callback()).then(() => value),
        reason => P.resolve(callback()).then(() => { throw reason })
    );
};