一、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); // 仅注册回绝的回调函数 }}