promisesaplus.com/
简单的 promise
是什么?(thenable/PromiseLike
)
但是一个真正的 promise
除去这两点还有一些细化的东西,具体是一个怎么样的对象,then
方法内部是什么处理
function isPromiseLike(value) {
return (
value !== null &&
(typeof value === "object" || typeof value === "function") &&
typeof value.then === "function"
);
}
实现 PromiseA+ 规范
-
定义工具方法,用于 class
中的内部使用
function isFunction(x) {
return typeof x === "function";
}
- 定义一个判断是否
thenable
(PromiseLike
)的方法
function isThenable(x) {
// 判断 x 是不是一个对象或者函数,并且 x.then 是一个函数
return (
((typeof x === "object" && x !== null) || isFunction(x)) &&
isFunction(x.then)
);
}
-
初始化一个 promise
构造函数,包含属性的定义,一个 constructor
构造方法以及 then
方法声明 定义内部变量,包含 state
( promise
的状态),data
(完成状态下的数据),reason
(拒绝状态下的数据),settledhandlers
(完成状态下的回调函数)
class MyPromise {
// Promise有三种状态
_state = "pending"; // 初始状态'pending' | 'fulfilled' | 'rejected'
_data = undefined; // promise 完成状态下的相关数据
_reason = undefined; // promise 拒绝状态下的相关数据
_settledhandlers = []; // 当前 promise 完成状态下的回调函数,为什么要定义成一个数组,是因为可能会有多个 then 方法
constructor(executor) {}
then(onFulfilled, onRejected) {}
}
为什么这些属性没有设置私有
Promise/A+ 规范只要求状态不可变,没要求可见性; ES6 官方 Promise 把 [[PromiseState]]
做成引擎级私有槽,外部无法访问; 自己实现时,用 #state
或 WeakMap
把它设为私有,是最佳实践而非强制。
-
完善构造函数的实现
// 构造函数接受一个执行器函数 executor
constructor(executor) {
// executor 必须是一个函数
if (!isFunction(executor)) {
throw new TypeError(`Promise resolver ${executor} is not a function`);
}
// 定义实例属性 resolve 和 reject
const resolve = (data) => {
resolvePromise(this, data);
};
// 这个简单
const reject = (err) => {
rejectPromise(this, err);
};
try {
// 执行过程中有错误,会直接抛出错误
executor(resolve, reject);
} catch (e) {
return reject(e);
}
}
具体的 resolve
和 reject
需要定义额外的方法去实现
-
其中,reject
方法考虑的内容较少,实现较为简单(只关注两件事,改变状态和更新 reason
)
function rejectPromise(prom, reason) {
// 当一个 promise 的状态确定后,状态和相关数据就不会再改变了,历史不可倒退
if (prom._state !== "pending") return; // 状态只能从 pending -> fulfilled/rejected
// 直接拒绝,修改promise的状态
prom._state = "rejected";
prom._reason = reason;
}
-
resolve
方法的实现,判断传入的值是不是一个 promise
,要去吸收状态,否则直接改变 promise
的状态
function resolvePromise(prom, x) {
// 当一个 promise 的状态确定后,状态和相关数据就不会再改变了,历史不可倒退
if (prom._state !== "pending") return; // 状态只能从 pending -> fulfilled/rejected
// 判断 x 是不是一个 promise(有可能是一个 thenable 对象)
if (isThenable(x)) {
// 判断 x 和 prom 是不是同一个对象
if (x === prom) {
return rejectPromise(
prom,
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
// 不是同一个对象,要去吸收 x 的状态,还要增加一个 microtask 队列
queueMicrotask(() => {
x.then(
(data) => {
// x 成功了,用 data 去 resolve prom
resolvePromise(prom, data); // 递归解析
},
(err) => {
// x 失败了,用 err 去 reject prom
rejectPromise(prom, err);
}
);
});
} else {
prom._state = "fulfilled";
prom._data = x;
}
}
-
实现 then
方法,就处理两个问题,回调什么时候调用,以及 then
方法的返回新的 promise
状态是什么
then(onFulfilled, onRejected) {
// then 方法返回一个新的 promise
const prom = new MyPromise((resolve, reject) => {});
// 为什么要定义成一个数组,是因为可能会有多个 then 方法
// 这里的回调函数要等到当前 promise 状态确定后才能调用
this._settledhandlers.push({
onFulfilled,
onRejected,
prom, // 当前 then 方法返回的 promise
});
// 数组里面push的内容什么时候执行呢?当状态确定后执行 通过一个flushHandles函数
flushHandlers(this);
return prom;
}
flushHandlers
方法是依次执行 promise
完成状态下的回调函数,通过 then
方法添加
// 将curpromise的_settledhandlers数组中的回调函数依次执行 所有回调依次处理
function flushHandlers(curPromise) {
if (curPromise._state === "pending") return; // 状态还是pending 直接返回
// 状态已经确定了 可能是fulfilled 也可能是rejected
// 让这些回调函数依次执行
const settledhandlers = curPromise._settledhandlers; //取出所有的回调
// 将后续的处理放入微任务队列中执行 是将整个放入,不是循环一个一个放入
queueMicrotask(() => {
while (settledhandlers.length) {
// 这个prom 和传入的curPromise不一样,是then方法中new的那个promise
// 取出第一个回调,需要清空原数组
const { onFulfilled, onRejected, prom } = settledhandlers.shift();
// 具体处理回调和prom的状态
// 判断,要是 onfocusfilled/onRejected 不是函数,就直接用当前promise的值去resolve/reject
if (!isFunction(onFulfilled) && curPromise._state === "fulfilled") {
// 状态穿透
resolvePromise(prom, curPromise._data);
continue; // 继续下一个
}
// 同样的,当前状态为失败,但是不是函数
if (!isFunction(onRejected) && curPromise._state === "rejected") {
// 状态穿透
rejectPromise(prom, curPromise._reason);
continue; // 继续下一个
}
// 走到这里,说明是函数,那就运行其中一个回调,状态结果取决于回调的结果是否报错,因此要try catch
let result;
try {
// 不报错就resolve;
result =
curPromise._state === "fulfilled"
? onFulfilled(curPromise._data)
: onRejected(curPromise._reason);
} catch (error) {
// 报错就reject
rejectPromise(prom, error);
continue; // 继续下一个
}
// 走到这里,说明没有报错,用result去resolve
// 只要返回了一个结果,不管是成功还是失败,都要用这个结果去resolve
resolvePromise(prom, result);
}
});
}
该方法为处理后续的回调,在状态确定后或者调用 then
方法时执行
因此需要额外在状态确定时调用一次,涉及到状态调用的地方有 rejectPromise
和 resolvePromise
两个方法
function rejectPromise(prom, reason) {
// 当一个 promise 的状态确定后,状态和相关数据就不会再改变了,历史不可倒退
if (prom._state !== "pending") return; // 状态只能从 pending -> fulfilled/rejected
// 直接拒绝,修改promise的状态
prom._state = "rejected";
prom._reason = reason;
// 状态确定后,去执行回调函数
flushHandlers(prom);
}
function resolvePromise(prom, x) {
// 当一个 promise 的状态确定后,状态和相关数据就不会再改变了,历史不可倒退
if (prom._state !== "pending") return; // 状态只能从 pending -> fulfilled/rejected
// 判断 x 是不是一个 promise(有可能是一个 thenable 对象)
if (isThenable(x)) {
xxxx.....
} else {
prom._state = "fulfilled";
prom._data = x;
// 状态确定后,去执行回调函数
flushHandlers(prom);
}
}
-
调用测试,和 Promise
方法进行对比
process.on("unhandledRejection", () => {
console.log("process unhandledRejection");
});
const p = new Promise((resolve, reject) => {
resolve(1);
});
const p_my = new MyPromise((resolve, reject) => {
resolve(1);
});
console.log("start", p._state);
const p1 = p.then(123).then(() => {
return "p1 fulfilled";
});
const p2 = p_my.then(123).then(() => {
return "p2 fulfilled";
});
setTimeout(() => {
console.log("p=>", p);
console.log("p_my=>", p_my);
console.log("p1=>", p1);
console.log("p2=>", p2);
}, 0);
// p=> Promise { 1 }
// p_my=> MyPromise {
// _state: 'fulfilled',
// _data: 1,
// _reason: undefined,
// _settledhandlers: []
// }
// p1=> Promise { 'p1 fulfilled' }
// p2=> MyPromise {
// _state: 'fulfilled',
// _data: 'p2 fulfilled',
// _reason: undefined,
// _settledhandlers: []
// }
完整写法
// 贴合es6的写法
function isFunction(x) {
return typeof x === "function";
}
function isThenable(x) {
// 判断 x 是不是一个对象或者函数,并且 x.then 是一个函数
return (
((typeof x === "object" && x !== null) || isFunction(x)) &&
isFunction(x.then)
);
}
// 处理后续的回调 在状态确定后 或者 调用 then 方法执行
// 将curpromise的_settledhandlers数组中的回调函数依次执行 所有回调依次处理
function flushHandlers(curPromise) {
if (curPromise._state === "pending") return; // 状态还是pending 直接返回
// 状态已经确定了 可能是fulfilled 也可能是rejected
// 让这些回调函数依次执行
const settledhandlers = curPromise._settledhandlers; //取出所有的回调
// 将后续的处理放入微任务队列中执行 是将整个放入,不是循环一个一个放入
queueMicrotask(() => {
while (settledhandlers.length) {
// 这个prom 和传入的curPromise不一样,是then方法中new的那个promise
// 取出第一个回调,需要清空原数组
const { onFulfilled, onRejected, prom } = settledhandlers.shift();
// 具体处理回调和prom的状态
// 判断,要是 onfocusfilled/onRejected 不是函数,就直接用当前promise的值去resolve/reject
if (!isFunction(onFulfilled) && curPromise._state === "fulfilled") {
// 状态穿透
resolvePromise(prom, curPromise._data);
continue; // 继续下一个
}
// 同样的,当前状态为失败,但是不是函数
if (!isFunction(onRejected) && curPromise._state === "rejected") {
// 状态穿透
rejectPromise(prom, curPromise._reason);
continue; // 继续下一个
}
// 走到这里,说明是函数,那就运行其中一个回调,状态结果取决于回调的结果是否报错,因此要try catch
let result;
try {
// 不报错就resolve;
result =
curPromise._state === "fulfilled"
? onFulfilled(curPromise._data)
: onRejected(curPromise._reason);
} catch (error) {
// 报错就reject
rejectPromise(prom, error);
continue; // 继续下一个
}
// 走到这里,说明没有报错,用result去resolve
// 只要返回了一个结果,不管是成功还是失败,都要用这个结果去resolve
resolvePromise(prom, result);
}
});
}
function rejectPromise(prom, reason) {
// 当一个 promise 的状态确定后,状态和相关数据就不会再改变了,历史不可倒退
if (prom._state !== "pending") return; // 状态只能从 pending -> fulfilled/rejected
// 直接拒绝,修改promise的状态
prom._state = "rejected";
prom._reason = reason;
// 状态确定后,去执行回调函数
flushHandlers(prom);
}
function resolvePromise(prom, x) {
// 当一个 promise 的状态确定后,状态和相关数据就不会再改变了,历史不可倒退
if (prom._state !== "pending") return; // 状态只能从 pending -> fulfilled/rejected
// 判断 x 是不是一个 promise(有可能是一个 thenable 对象)
if (isThenable(x)) {
// 判断 x 和 prom 是不是同一个对象
if (x === prom) {
return rejectPromise(
prom,
new TypeError("Chaining cycle detected for promise #<Promise>")
);
}
// 不是同一个对象,要去吸收 x 的状态,还要增加一个 microtask 队列
queueMicrotask(() => {
x.then(
(data) => {
// x 成功了,用 data 去 resolve prom
resolvePromise(prom, data); // 递归解析
},
(err) => {
// x 失败了,用 err 去 reject prom
rejectPromise(prom, err);
}
);
});
} else {
prom._state = "fulfilled";
prom._data = x;
// 状态确定后,去执行回调函数
flushHandlers(prom);
}
}
class MyPromise {
// Promise有三种状态
_state = "pending"; // 初始状态'pending' | 'fulfilled' | 'rejected'
_data = undefined; // promise 完成状态下的相关数据
_reason = undefined; // promise 拒绝状态下的相关数据
_settledhandlers = []; // 当前 promise 完成状态下的回调函数
// 构造函数接受一个执行器函数 executor
constructor(executor) {
// executor 必须是一个函数
if (!isFunction(executor)) {
throw new TypeError(`Promise resolver ${executor} is not a function`);
}
// 定义实例属性
const resolve = (data) => {
resolvePromise(this, data);
};
// 这个简单
const reject = (err) => {
rejectPromise(this, err);
};
try {
// 执行过程中有错误,会直接抛出错误
executor(resolve, reject);
} catch (e) {
return reject(e);
}
}
// 就处理两个问题,回调什么时候调用,以及 then 方法的返回新的 promise 状态是什么
then(onFulfilled, onRejected) {
// 这里的回调函数要等到当前 promise 状态确定后才能调用
const prom = new MyPromise((resolve, reject) => {});
// 为什么要定义成一个数组,是因为可能会有多个 then 方法
// 这里的回调函数要等到当前 promise 状态确定后才能调用
this._settledhandlers.push({
onFulfilled,
onRejected,
prom, // 当前 then 方法返回的 promise
});
// 数组里面push的内容什么时候执行呢?当状态确定后执行 通过一个flushHandles函数
flushHandlers(this);
return prom;
}
}