一、Promise/A+ 标准

① Promise 是一个或者函数外部领有3个状态,别离为pending(期待)fulfilled(执行、实现)rejected(回绝、未实现)
默认为pending状态,即Promise对象刚创立的时候状态为pending,并且pending状态能够转换fulfilled或者rejected
fulfilled和rejected为最终的状态一旦变为fulfilled或者rejected,那么将无奈转变为其余状态

② Promise须要对外提供一个then办法

promise.then(onFulfilled, onRejected)

如果可选参数onFulfilled和onRejected不为函数时应该被疏忽

onFulfilled和onRejected函数都应该是异步执行的;

当调用 onFulfilled 函数时,会将以后 Promise 的值作为参数传入,并且只能调用一次

当调用 onRejected 函数时,会将以后 Promise 的失败起因作为参数传入,并且只能调用一次

then函数的返回值依然为Promise,以便进行链式调用;

resolvePromise
then办法会创立并返回一个Promise对象,then中注册的回调函数会返回各种值必须进行校验

then办法返回的promise不能与then中回调函数返回值x相等,否则须要抛出谬误

如果是then回调函数返回值为一个非Promise对象,则间接用then返回的promise对象的resolve办法,resolve(x)即可。

如果then回调函数返回值x为一个Promise对象或者一个带then办法的对象或函数,那么须要执行其then办法注册回调拿到Promise或类Promise对象的值作为then返回的promise的值,如果值依然为Promise对象则须要进行递归操作

二、实现Promise

① 依据第一条标准,Promise是一个类或者函数,所以咱们先将Promise定义成一个类,同时外部有三个状态,咱们将其定义为常量

var PENDING = "pending"; // 期待状态var FULFILLED = "fulfilled"; // 执行、实现状态var REJECTED = "rejected"; // 回绝、未实现状态class Promise {    constructor() {        this.state = PENDING; // Promise对象创立实现后默认为期待状态    }}

② 咱们在创立Promise的时候会传入一个函数,该函数会在创立Promise对象的时候立刻执行,并且会接管两个参数,别离用于执行回绝以后Promise对象,即批改以后Promise对象的状态。Promise是用于解决异步的,所以在Promise状态变为实现的时候可能会接管到异步操作执行的后果在Promise状态变为未实现的时候可能会接管到失败的起因,所以Promise外部还须要保留异步操作的后果value失败的起因reason

......class Promise {    constructor(executor) { // 传入执行器函数        ......        this.value = undefined; // 保留异步操作的后果        this.reason = undefined; // 保留失败的起因        const resolve = (value) => {            this.value = value;            this.state = FULFILLED; // 将Promise对象的状态改为实现状态        }        const reject = (reason) => {            this.reason = reason;            this.state = REJECTED; // 将Promise对象的状态改为未实现状态        }        try {            executor(resolve, reject); // 执行器由用户传入可能会产生谬误,所以须要进行捕捉        } catch(e) {            reject(e);        }    }}

③ 这里还存在一个问题,就是Promise必须是单次执行的,Promise的状态一旦从pending状态批改为fulfilled或者rejected,就不能再发生变化,从fulfilled变为fulfilled也不能够,也就是说resolve或者reject只能执行一次。所以咱们须要对resolve和reject外部进行判断,如果状态曾经变动了则不再执行了,如:

......class Promise {    constructor(executor) { // 传入执行器函数        ......        const resolve = (value) => {            if (this.state === PENDING) { // 避免用户屡次resolve,以第一次resolve为准                ......            }        }        const reject = (reason) => {            if (this.state === PENDING) { // 避免用户屡次reject                ......            }        }        ......    }}

④ 给Promise增加一个then函数,then函数接管onFulfilled, onRejected两个函数作为参数,别离用于解决Promise实现时和未实现时的回调函数,如果不是函数,则要进行初始化为一个函数,如:

class Promise {    then(onFulfilled, onRejected) {        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => { // 如果onFulfilled不是函数,则初始化一个实现处理函数            return value;        };        onRejected = typeof onRejected === "function" ? onRejected : (reason) => { // 如果onRejected不是函数,则初始化一个未实现处理函数            throw reason; // 传什么就抛出什么        }    }}

⑤ then办法其实就是一个注册回调的过程,当调用then的这个Promise对象的状态变为实现状态就能够执行onFulfilled回调函数,当Promise对象的状态变为回绝状态就能够执行onRejected回调函数了。所以回调函数的执行依赖于调用then的Promise的状态。同时为了反对链式调用,then办法还须要返回一个Promise对象。依据后面的Promise标准,传入的回调函数必须异步执行,这里用setTimeout进行模仿。

class Promise {    then(onFulfilled, onRejected) {        ......        let promise;        switch(this.state) {            case FULFILLED: // 调用then办法的时候,以后Promise状态曾经变成实现状态,则可用立刻执行实现的回调函数                promise = new Promise((resolve, reject) => {                    setTimeout(() => {                        try {                            let x = onFulfilled(this.value);                        } catch(e) {                            console.log(e); // 打印错误信息                            reject(e);                        }                    });                });                break;            case REJECTED:                promise = new Promise((resolve, reject) => {                    setTimeout(() => {                        try {                            let x = onRejected(this.reason);                        } catch(e) {                            reject(e);                        }                    });                }                break;            case PENDING:                promise = new Promise((resolve, reject) => {                    // TODO                });                break;        }        return promise;    }}

⑥ 当调用then的Promise对象处于pending状态的时候,此时通过then注册的回调函数不能立刻执行,必须期待Promise的状态变为最终状态能力执行注册的回调函数。这里就波及到了一个公布订阅模式。咱们能够先将回调函数保存起来,那么什么时候Promise才会变成最终状态呢?那就是调用resolve或reject的时候,所以咱们能够在调用resolve或reject的时候,取出注册的回调函数而后执行即可。

class Promise {    constructor(executor) {        const resolve = (value) => {            if (this.state === PENDING) { // 避免用户屡次resolve,以第一次resolve为准                ......                this.onFulfilleds.forEach(fn => fn()); // 取出then中注册的实现回调函数并执行            }        };        const reject = (reason) => {            if (this.state === PENDING) { // 避免用户屡次reject                ......                this.onRejecteds.forEach(fn => fn()); // 取出then中注册的回绝回调函数并执行            }        };    }    then(onFulfilled, onRejected) {        ......        switch(this.state) {            case PENDING:                promise = new Promise((resolve, reject) => {                    this.onFulfilleds.push(() => {                        try {                            let x = onFulfilled(this.value);                        } catch(e) {                            console.log(e); // 打印错误信息                            reject(e);                        }                    });                    this.onRejecteds.push(() => {                        try {                            let x = onRejected(this.reason);                        } catch(e) {                            reject(e);                        }                    });                });                break;        }    }}

⑦ 接下来就是要解决then注册的回调函数的返回值了,因为回调函数的返回值可能是各种各样的状况,可能是一般的值,可能是Promise对象,也可能是带then办法的对象,所以咱们要一一进行解决。这里咱们应用一个独自的办法resolvePromise()进行各种状况的解决,如:

// 传入then()办法中创立的Promise对象,回调函数的返回值x,then()办法中创立的Promise的resolve、rejectconst resolvePromise = function(promise, x, resolve, reject) {    // TODO}class Promise {    constructor(executor) { // 传入执行器函数        ......    }    then(onFulfilled, onRejected) {        case FULFILLED:            promise = new Promise((resolve, reject) => {                ......                let x = onFulfilled(this.value);                resolvePromise(promise, x, resolve, reject); // 解决回调函数的返回值            });        case REJECTED:            promise = new Promise((resolve, reject) => {                ......                let x = onRejected(this.reason);                resolvePromise(promise, x, resolve, reject); // 解决回调函数的返回值            });        case PENDING:            this.onFulfilleds.push(() => {                let x = onFulfilled(this.value);                resolvePromise(promise, x, resolve, reject); // 解决回调函数的返回值            });            this.onRejecteds.push(() => {                let x = onRejected(this.reason);                resolvePromise(promise, x, resolve, reject); // 解决回调函数的返回值            });    }}

三、实现resolvePromise

① 如果回调函数返回值与then()办法中创立的Promise对象雷同则抛出谬误,这相当于是本人等本人会进入死循环

let p1 = new Promise((resolve, reject) => {    resolve(1);})let p2 = p1.then((value) => { // p2即then办法内创立Promise对象    return p2;});// 后果抛出谬误,显示Chaining cycle detected for promise #<Promise>
const resolvePromise = function(promise, x, resolve, reject) {    if (promise === x) { // 禁止resolve本人        throw new Error("Chaining cycle detected for promise #<Promise>");    }}

② 如果回调函数返回的是一个Promise对象或者带then办法的类Promise对象,又或者一个函数,因为函数上也可能有then办法,那么咱们须要取出then办法并执行,对于Promise对象而言,then办法的执行就会注册相应的回调函数等Promise状态变为最终状态后就会执行对应的回调函数,回调函数执行后就能够拿到Promise对象的value值,而后将该value值作为调用then办法创立的Promise的对象的value值

const resolvePromise = function(promise, x, resolve, reject) {    ......    if ((x && typeof x === "object") || typeof x === "function") { // 如果是对象或者函数,函数也可能有then办法        let executed;        try {            let then = x.then; // 尝试取出then办法            if (typeof then === "function") { // 如果该对象上存在then办法,那么是个Promise对象或者蕴含then办法的对象                then.call(x, function (y) { // 执行then办法,对于真正的Promise对象,则会注册回调,等到状态变动后,回调函数会执行,回调中能接管到Promise的value值                    if (executed) return;                    executed = true; // 注册的回调函数只能执行一次                    resolvePromise(promise, y, resolve, reject); // 返回值还可能是一个Promise对象,故须要递归直到变为一般值为止                }, function (e) {                    if (executed) return;                    executed = true;                    reject(e);                });            } else { // 不蕴含then办法的一般对象,间接resolve即可                resolve(x);                  }        } catch(e) {            if (executed) return;            executed = true;            reject(e);        }    } else {        resolve(x);    }}

四、实现catch

catch能够看做是一个非凡的then办法其外部会调用then()办法,然而仅注册回绝的回调函数,这也就是then(onFulfilled, onRejected)和then(onFulfilled).catch(onRejected)的区别,如果将onRejected写到then中,那么当then的onFulfilled产生谬误的时候onRejected就无奈捕捉到其中的谬误,而写到catch中,那么就相当于是下一个then()办法,故能捕捉到上一个then()办法中产生的谬误。

class Promise {    catch(onRejected) {        return this.then(null, onRejected); // 仅注册回绝的回调函数    }}

五、总结

Promise其实就是一个类,外部有state、value、reason等属性,别离用于存储以后Promise的状态执行胜利后的返回值执行失败的起因,同时外部还提供了resolve、reject两个办法,这两个办法会以参数的模式传递给执行器,即传递到内部,以便批改Promise的状态。
Promise还提供了一个then办法用于注册回调函数,注册回调的时候与以后Promise的状态无关,如果是最终状态,则立刻执行,如果是期待状态,则先保存起来等到调用resolve或reject办法的时候再取出回调并执行。注册的回调函数可能会返回各种各样的值:
如果返回的是一般值,那么间接用then返回的Promise的resolve办法resolve即可;
如果返回的是Promise对象或者是带then办法的对象或函数,那么须要调用其then办法并注册一个自定义回调用于接管以后Promise的值,等该Promise变为最终状态后会执行回调就能够拿到其value,最初将其作为then返回的Promise的value,即resolve(x)。
残缺源码如下:

var PENDING = "pending"; // 期待状态var FULFILLED = "fulfilled"; // 执行、实现状态var REJECTED = "rejected"; // 回绝、未实现状态// 传入then()办法中创立的Promise对象,回调函数的返回值x,then()办法中创立的Promise的resolve、rejectconst resolvePromise = function(promise, x, resolve, reject) {    if (promise === x) { // 禁止resolve本人        throw new Error("Chaining cycle detected for promise #<Promise>");    }    if ((x && typeof x === "object") || typeof x === "function") { // 如果是对象或者函数,函数也可能有then办法        let executed;        try {            let then = x.then; // 尝试取出then办法            if (typeof then === "function") { // 如果该对象上存在then办法,那么是个Promise对象或者蕴含then办法的对象                then.call(x, function (y) { // 执行then办法,对于真正的Promise对象,则会注册回调,等到状态变动后,回调函数会执行,回调中能接管到Promise的value值                    if (executed) return;                    executed = true; // 注册的回调函数只能执行一次                    resolvePromise(promise, y, resolve, reject); // 返回值还可能是一个Promise对象,故须要递归直到变为一般值为止                }, function (e) {                    if (executed) return;                    executed = true;                    reject(e);                });            } else { // 不蕴含then办法的一般对象,间接resolve即可                resolve(x);            }        } catch(e) {            if (executed) return;            executed = true;            reject(e);        }    } else {        resolve(x);    }}class Promise {    constructor(executor) { // 传入执行器函数        this.state = PENDING; // Promise对象创立实现后默认为期待状态        this.value = undefined; // 保留异步操作的后果        this.reason = undefined; // 保留失败的起因        this.onFulfilleds = []; // 保留then中注册的实现回调函数        this.onRejecteds = []; // 保留then中注册的回绝回调函数        const resolve = (value) => {            if (this.state === PENDING) { // 避免用户屡次resolve,以第一次resolve为准                this.value = value;                this.state = FULFILLED; // 将Promise对象的状态改为实现状态                this.onFulfilleds.forEach(fn => fn()); // 取出then中注册的实现回调函数并执行            }        };        const reject = (reason) => {            if (this.state === PENDING) { // 避免用户屡次reject                this.reason = reason;                this.state = REJECTED; // 将Promise对象的状态改为未实现状态                this.onRejecteds.forEach(fn => fn()); // 取出then中注册的回绝回调函数并执行            }        };        try {            executor(resolve, reject); // 执行器由用户传入可能会产生谬误,所以须要进行捕捉        } catch(e) {            reject(e);        }    }    then(onFulfilled, onRejected) {        onFulfilled = typeof onFulfilled === "function" ? onFulfilled : (value) => { // 如果onFulfilled不是函数,则初始化一个实现处理函数            return value;        };        onRejected = typeof onRejected === "function" ? onRejected : (reason) => { // 如果onRejected不是函数,则初始化一个未实现处理函数            throw reason; // 传什么就抛出什么        }        let promise;        switch(this.state) {            case FULFILLED: // 调用then办法的时候,以后Promise状态曾经变成实现状态,则可用立刻执行实现的回调函数                promise = new Promise((resolve, reject) => {                    setTimeout(() => {                        try {                            let x = onFulfilled(this.value);                            resolvePromise(promise, x, resolve, reject);                        } catch(e) {                            console.log(e);                            reject(e);                        }                    });                });                break;             case REJECTED:                promise = new Promise((resolve, reject) => {                    setTimeout(() => {                        try {                            let x = onRejected(this.reason);                            resolvePromise(promise, x, resolve, reject);                        } catch(e) {                            reject(e);                        }                    });                });                break;            case PENDING:                promise = new Promise((resolve, reject) => {                    this.onFulfilleds.push(() => {                        try {                            let x = onFulfilled(this.value);                            resolvePromise(promise, x, resolve, reject);                        } catch(e) {                            reject(e);                        }                    });                    this.onRejecteds.push(() => {                        try {                            let x = onRejected(this.reason);                            resolvePromise(promise, x, resolve, reject);                        } catch(e) {                            reject(e);                        }                    });                });                break;            }        return promise;    }    catch(onRejected) {        return this.then(null, onRejected); // 仅注册回绝的回调函数    }}