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