前言
作为一个一年前端的新人,在学习promise过程中遇到了很多的问题,学到的东西很零散,于是决定将了解的相关知识整理下。
期约(Promise)基础
Promise是ECMAScript6新增的引用类型,可以通过new操作符来实例化,创建新的Promise对象时必须要传入一个执行器(executor)函数作为参数。
let p = new Promise(()=>{});
console.log(p);//此时状态为pedding
1.Promise的属性
根据typeof 可以看出 promise的实例是对象类型
let p = new Promise((resolve, reject) => resolve());
console.log(typeof p); // object
promise对象主要有两个不可枚举的属性,PromiseState 和 PromiseResult,其中PromiseState存储promise的状态,PromiseResult存储promise的结果
2.Promise的三种状态
1.pedding 待定,是期约最初始的状态
2.fulilled 兑现,也称解决,代表期约成功的状态
3.rejected 拒绝,代表期约失败的状态
这三种状态间的转换是不可逆的,并且期约的状态只能改变一次。只能由pedding => fulilled 或者由 pedding => rejected 。
3.Promise状态间的转换
promise的状态是私有的,状态之间的转换只能在promise的执行器函数中完成。执行器函数有两个函数参数,通常被命名为resolve() 和reject()。 调用resolve() 会把状态从待定转化为兑现
let p = new Promise((resolve, reject) => {
resolve('成功');
});
console.log(p); //状态为fulilled
调用reject() 会把状态从待定转化为拒绝
let p = new Promise((resolve, reject) => {
reject('失败');
});
console.log(p); //此时状态为 rejected,
//但由于promise的错误结果没有捕获处理,控制台会报错
前面的这些并不涉及到异步操作,在初始化promise的时候,执行器函数已经改变了每个期约的状态。关键在于,执行器函数是同步执行的,是promise的初始化程序。可以看下面这个例子
let p = new Promise((resolve, reject) => {
resolve('成功');
console.log(1);
});
console.log(2);
//执行结果为 1 2
4.Promise.resolve()
promise并非一开始就必须处于待定状态,可以通过Promise.resolve()静态方法实例化一个fulilled状态的promise。下面两者是等价的。
let p1 = new Promise((resolve, reject) => resolve());
let p2 = Promise.resolve();
这个fulilled状态的promise的结果对应着Promise.resolve()里面的第一个参数。 实际上resolve()静态方法可以把任何值都转化为promise,传入多个参数只取第一个参数,多余的参数会被忽略。如果传入的参数是一个新的promise,则状态与结果与传入的promise保持一致。
let p1 = new Promise((resolve, reject) => { });
let p = Promise.resolve(p1);
console.log(p);//PromiseState:pedding PromiseResult:undefined
let p1 = new Promise((resolve, reject) => resolve(3));
let p = Promise.resolve(p1);
console.log(p); //PromiseState:fulfilled PromiseResult:3
let p1 = new Promise((resolve, reject) => reject(3));
let p = Promise.resolve(p1);
console.log(p); //PromiseState:rejected PromiseResult:3
5.Promise.reject()
与Promise.resolve()类似 Promise.reject()会实例化一个rejected状态的promise并抛出一个异步错误,这个错误不能通过try/catch捕获,只能通过拒绝处理程序捕获
try {
let p = Promise.reject(3);
p.catch(e => console.log(e)); //3
} catch {
console.log('---');
}
与resolve()不同的是,如果传入的是一个promise,那么这个promise就会成为拒绝期约的结果。
let p1 = new Promise((resolve, reject) => resolve(3));
let p2 = new Promise((resolve, reject) => reject(3));
let p3 = new Promise((resolve, reject) => { });
let p_1 = Promise.reject(p1);
console.log(p_1); //PromiseState:rejected PromiseResult:promise
let p_2 = Promise.reject(p2);
console.log(p_2); //PromiseState:rejected PromiseResult:promise
let p_3 = Promise.reject(p3);
console.log(p_3); //PromiseState:rejected PromiseResult:promise
Promise的实例方法
1 Promise.prototype.then()
Promise.prototype.then()是为Promise实例添加处理程序的主要方法,then()方法最多接收两个参数,onResolved处理程序和onReject处理程序。这两个参数是可选的,可以使用null进行站位,分别会在Promise进入fulilled 和 rejected 状态时执行。
let p1 = new Promise((resolve, reject) => resolve());
let p2 = new Promise((resolve, reject) => reject());
p1.then(() => { console.log('resolve') },
() => { console.log('reject'); }) //resolve
p2.then(() => { console.log('resolve') },
() => { console.log('reject'); }) //reject
传给then()方法的任何非函数类型参数都会被静默忽略。 then()方法会返回一个新的Promise实例
let p1 = new Promise((resolve, reject) => { });
p1.then();
console.log(p1.then()); //Promise<pedding>
then()方法返回的新Promise实例,这个Promise实例是基于onResolve处理程序返回的值构建,即返回值会通过Promise.resolve() 包装生成新的Promise。新的Promise的状态与上一个Promise状态保持一致。
let p1 = new Promise((resolve, reject) => { resolve() });
let p2 = p1.then(() => 2);
//PromiseState:fulfilled PromiseResult:2
如果then()方法没有提供处理程序,那么Promise.resolve()会包装上一次Promise解决之后的值。
let p1 = new Promise((resolve, reject) => { });
p1.then(); //PromiseState:pedding PromiseResult:undefined
let p2 = new Promise((resolve, reject) => { resolve(3) });
p2.then(); //PromiseState:fulilled PromiseResult:3
let p3 = new Promise((resolve, reject) => { reject(3) });
p3.then(); //PromiseState:rejected PromiseResult:3
如果没有显示的返回语句,则Promise.resolve()会包装默认的返回值undefined;
2 Promise.prototype.catch()
主要用于给Promise添加拒绝处理程序,该方法只接收一个函数参数:onRejected作为作为处理程序。 与它有相同效果的还有 Promise.prototype.then(null,onRejected); 下面这两种效果是等同的。
let p = Promise.reject('失败');
p.then(null, (error) => { console.log(error); }); //失败
p.catch((error) => { console.log(error); }); //失败
除此之外,catch方法的返回值也与 Promise.prototype.then 方法中的 onRejected 处理程序是一样的。
3 Promise.prototype.finally()
Promise.prototype.finally()方法用于给Promise添加最终的处理的程序,接收一个函数参数onFinally作为处理,在Promise转化为成功状态或者失败状态都会执行,onFinally不清楚Promise的最终状态,也不接受参数。
finally()方法返回一个新的Promise实例。但由于onFinally是状态无关的方法,无论上一级Promise的状态如何,都会原样后传
let p1 = new Promise(() => { });
//PromiseState:pedding PromiseResult:undefined
let p2 = p1.finally();
//PromiseState:pedding PromiseResult:undefined
let p3 = p2.finally(() => Promise.reject());
//PromiseState:pedding PromiseResult:undefined
如果onFinally处理程序返回了一个拒绝Promise或抛出异常,则会返回对应状态的Promise。 resolve->rejected 或者 pedding->pedding
后续会继续更新...