study / Promise对象

作者 GaoGe 日期 2019-05-18
ES6
study / Promise对象

promise的状态改变有以下两种情况:
pending -> resolved 进行时 -> 已完成
pending -> rejected 进行时 -> 已失败

异步操作的结果决定当前为哪一种状态,状态改变之后会一直保持,可以在任何时候获得。下面是一个详细的例子:

let promise = new Promise(function(resolve,reject){
console.log("异步操作1");
if("请求成功"){
resolve(value);
throw new Error("test"); // 对应5,抛出无效
} else {
reject(error);
}
});

promise.then(
(value) => {
console.log("第一个回调函数,状态变为resolved时调用");
return getJSON(value); //第二个请求方法
}
() => console.log("第二个回调函数,状态变为rejected时调用"),
).then(
() => console.log("第二个请求状态改变后的resolved回调"),
() => console.log("第二个请求状态改变后的rejected回调"),
).catch(
(error) => console.log("出错了:", error);
);

关于以上例子的解释:

  1. promise 新建后立即执行
  2. then方法定义在原型对象Promise.prototype上,接受两个回调作为参数,第一个是resolved状态的回调,第二个是rejected状态的回调(可选)
  3. then方法返回新的Promise实例,因此可以采用链式方法.then().then()
  4. 第一个函数请求成功的回调里发送第二个请求,当请求成功时将第二个请求的状态置为resolved,且调用第二个请求的then方法的resolved回调,失败调rejected
  5. 如果Promise状态已经变成resolved,再抛出错误无效
  6. 错误具有冒泡性质,总是会被下一个catch语句捕获
  7. 上面代码中有三个Promise对象:一个由 getJSON产生,两个由then产生。它们之中任何一个抛出的错误,都会被最后一个catch捕获。
  8. then方法指定的回调函数,如果运行中抛出错误,也会被catch方法捕获。一般不要在then方法里定义rejected回调,尽量使用catch方法。
    原因:catch可以捕获前面then执行的错误,更接近同步的方法(try/catch)

Promise.resolve()

将现有对象转为Promise对象,Promise.resolve方法参数有以下四种情况:

  1. 参数是promise实例 — 不作任何处理,原封返回实例
  2. 参数是具有then方法的对象 — 将其转为Promise对象,然后立即执行该对象的then方法
  3. 参数不是具有then方法的对象,或根本就不是对象 — 返回一个新的Promise对象,状态为Resolved
  4. 不带参数 — 直接返回一个Resolved状态的Promise对象

Promise.all()

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

p的状态由p1、p2、p3决定:

  1. p1、p2、p3都成功,p状态为fulfilled。p1、p2、p3的返回值组成一个数组,传递给p的回调函数
  2. p1、p2、p3有一个失败,p状态为rejected。第一个被reject的实例的返回值,传递给p的回调函数

Promise.race()

只要p1、p2、p3中有一个实例状态改变,p状态就跟着改变。率先改变的 Promise 实例的返回值,就传递给p的回调函数

Promise.race方法的参数与Promise.all方法一样,如果不是 Promise 实例,就会先调用下面讲到的Promise.resolve方法,将参数转为 Promise 实例,再进一步处理

Promise.reject()

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

done()

Promise对象的回调链,不管以then方法或catch方法结尾,要是最后一个方法抛出错误,都有可能无法捕捉到(因为Promise内部的错误不会冒泡到全局)。因此,我们可以提供一个done方法,总是处于回调链的尾端,保证抛出任何可能出现的错误。

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

finally()

finally方法用于指定不管Promise对象最后状态如何,都会执行的操作。它与done方法的最大区别,它接受一个普通的回调函数作为参数,该函数不管怎样都必须执行。

server.listen(0)
.then(function () {
// run test
})
.finally(server.stop);
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 })
);
}