共计 9529 个字符,预计需要花费 24 分钟才能阅读完成。
一、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); // 仅注册回绝的回调函数
}
}