初识Promise

136 阅读5分钟

前言

作为一个一年前端的新人,在学习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

后续会继续更新...