8. 完整实现Promise A+
Sunny-117 opened this issue · comments
// 记录Promise的三种状态
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
/**
* 运行一个微队列任务
* 把传递的函数放到微队列中
* @param {Function} callback
*/
function runMicroTask(callback) {
// 判断node环境
// 为了避免「变量未定义」的错误,这里最好加上前缀globalThis
// globalThis是一个关键字,指代全局对象,浏览器环境为window,node环境为global
if (globalThis.process && globalThis.process.nextTick) {
process.nextTick(callback);
} else if (globalThis.MutationObserver) {
const p = document.createElement("p");
const observer = new MutationObserver(callback);
observer.observe(p, {
childList: true, // 观察该元素内部的变化
});
p.innerHTML = "1";
} else {
setTimeout(callback, 0);
}
}
/**
* 判断一个数据是否是Promise对象
* @param {any} obj
* @returns
*/
function isPromise(obj) {
return !!(obj && typeof obj === "object" && typeof obj.then === "function");
}
class MyPromise {
/**
* 创建一个Promise
* @param {Function} executor 任务执行器,立即执行
*/
constructor(executor) {
this._state = PENDING; // 状态
this._value = undefined; // 数据
this._handlers = []; // 处理函数形成的队列
try {
executor(this._resolve.bind(this), this._reject.bind(this));
} catch (error) {
this._reject(error);
console.error(error);
}
}
/**
* 向处理队列中添加一个函数
* @param {Function} executor 添加的函数
* @param {String} state 该函数什么状态下执行
* @param {Function} resolve 让then函数返回的Promise成功
* @param {Function} reject 让then函数返回的Promise失败
*/
_pushHandler(executor, state, resolve, reject) {
this._handlers.push({
executor,
state,
resolve,
reject,
});
}
/**
* 根据实际情况,执行队列
*/
_runHandlers() {
if (this._state === PENDING) {
// 目前任务仍在挂起
return;
}
while (this._handlers[0]) {
const handler = this._handlers[0];
this._runOneHandler(handler);
this._handlers.shift();
}
}
/**
* 处理一个handler
* @param {Object} handler
*/
_runOneHandler({ executor, state, resolve, reject }) {
runMicroTask(() => {
if (this._state !== state) {
// 状态不一致,不处理
return;
}
if (typeof executor !== "function") {
// 传递后续处理并非一个函数
this._state === FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
const result = executor(this._value);
if (isPromise(result)) {
result.then(resolve, reject);
} else {
resolve(result);
}
} catch (error) {
reject(error);
console.error(error);
}
});
}
/**
* Promise A+规范的then
* @param {Function} onFulfilled
* @param {Function} onRejected
*/
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
this._runHandlers(); // 执行队列
});
}
/**
* 仅处理失败的场景
* @param {Function} onRejected
*/
catch(onRejected) {
return this.then(null, onRejected);
}
/**
* 无论成功还是失败都会执行回调
* @param {Function} onSettled
*/
finally(onSettled) {
return this.then(
(data) => {
onSettled();
return data;
},
(reason) => {
onSettled();
throw reason;
}
);
}
/**
* 更改任务状态
* @param {String} newState 新状态
* @param {any} value 相关数据
*/
_changeState(newState, value) {
if (this._state !== PENDING) {
// 目前状态已经更改
return;
}
this._state = newState;
this._value = value;
this._runHandlers(); // 状态变化,执行队列
}
/**
* 标记当前任务完成
* @param {any} data 任务完成的相关数据
*/
_resolve(data) {
this._changeState(FULFILLED, data);
}
/**
* 标记当前任务失败
* @param {any} reason 任务失败的相关数据
*/
_reject(reason) {
this._changeState(REJECTED, reason);
}
}
class myPromise {
constructor(executor) {//传入的函数(resolve,reject)=>{}
this.state = myPromise.PENDING
this.value = null
this.reason = null
this.onFulfilledFns = [] //异步回调队列
this.onRejectedFns = []
const resolve = value => {
if (this.state === myPromise.PENDING) {//只有在pendding才可修改状态
this.state = myPromise.FULFILLED
this.value = value
//执行异步回调
this.onFulfilledFns.forEach(fn => typeof fn === 'function' && fn())
}
}
const reject = reason => {
if (this.state === myPromise.PENDING) {//只有在pendding才可修改状态
this.state = myPromise.REJECTED
this.reason = reason
this.onRejectedFns.forEach(fn => fn())
}
}
executor(resolve, reject) //执行传入new promise的函数,执行resolve或reject
}
then(onFulfilled, onRejected) {//接收成功、失败的回调函数,或接收值, 值会透传
//处理值穿透
if (typeof onFulfilled !== 'function') onFulfilled = a => a
if (typeof onRejected !== 'function') {
onRejected = e => {
throw e
}
}
return new myPromise((resolve, reject) => {//返回new promise实例,链式调用
//执行微任务同步回调
if (this.state === myPromise.FULFILLED) {
// 封装execute
queueMicrotask(() => {
execute(onFulfilled, this.value, resolve, reject)//执行回调函数,将函数中的return用resolve包裹
})
} else if (this.state === myPromise.REJECTED) {
// 封装execute
queueMicrotask(() => execute(onRejected, this.reason, resolve, reject))
}
//执行异步回调,添加进数组,resolve时再调用函数
else {
this.onFulfilledFns.push(() =>
queueMicrotask(() =>
// 封装execute
execute(onFulfilled, this.value, resolve, reject)
)
)
this.onRejectedFns.push(() =>
queueMicrotask(() =>
// 封装execute
execute(onRejected, this.reason, resolve, reject)
)
)
}
})
}
}
function execute(cb, value, resolve, reject) {
try {
// 判断onFulfilled,onRejected返回值是否是Promise对象
const res = cb(value)
if (res instanceof myPromise) {
//如果是,那么新的Promise对象的状态就等于原来的Promise对象的状态
res.then(resolve, reject)
} else {
// 否则就是成功的状态
resolve(res)
}
} catch (e) {
reject(e)
}
}
myPromise.PENDING = 'pending'
myPromise.FULFILLED = 'fulfilled'
myPromise.REJECTED = 'rejected'
Promise A+规范要求obj是一个对象或函数,这样写是否是更合理一点
address: https://promisesaplus.com/#point-53
function isPromise(obj) {
return !!(obj && (typeof obj === "object" || typeof obj === 'function') && typeof obj.then === "function");
}
请问这两边都需要执行队列中的函数吗?有点没太明白
then(onFulfilled, onRejected) {
return new MyPromise((resolve, reject) => {
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
this._runHandlers(); // 执行队列
});
}
和
_changeState(newState, value) {
if (this._state !== PENDING) {
// 目前状态已经更改
return;
}
this._state = newState;
this._value = value;
this._runHandlers(); // 状态变化,执行队列
}
if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
// 如果 x 为对象或函数
try {
// 把 x.then 赋值给 then
var then = x.then;
} catch (e) {
// 如果取 x.then 的值时抛出错误 e ,则拒绝 promise
return reject(e);
}
/**
* 如果 then 是函数,将 x 作为函数的作用域 this 调用之。
* 传递两个回调函数作为参数,
* 第一个参数叫做 `resolvePromise` ,第二个参数叫做 `rejectPromise`
*/
if (typeof then === 'function') {
// 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用
let called = false; // 避免多次调用
try {
then.call(
x,
// 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y)
y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
},
// 如果 rejectPromise 以据因 r 为参数被调用,拒绝 promise
r => {
if (called) return;
called = true;
reject(r);
}
)
} catch (e) {
/**
* 如果调用 then 方法抛出了异常 e
* 如果 resolvePromise 或 rejectPromise 已经被调用,则忽略之
*/
if (called) return;
called = true;
// 拒绝 promise
reject(e);
}
} else {
如果 then 不是函数,以 x 为参数执行 promise
resolve(x);
}
function Promise(executor) {
this.state = "pending";
this.value = undefined;
this.reason = undefined;
// 保存成功回调
this.onResolvedCallbacks = [];
// 保存失败回调
this.onRejectedCallbacks = [];
let _this = this;
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
function resolve(value) {
if (_this.state === "pending") {
_this.state = "resolved";
_this.value = value;
_this.onResolvedCallbacks.forEach((cb) => cb(value));
}
}
function reject(reason) {
if (_this.state === "pending") {
_this.state = "rejected";
_this.reason = reason;
_this.onRejectedCallbacks.forEach((cb) => cb(reason));
}
}
}
Promise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (err) => {
throw err;
};
let promise2 = new Promise((resolve, reject) => {
// 等待态判断,此时异步代码还未走完,回调入数组队列
if (this.state === "pending") {
this.onResolvedCallbacks.push(() => {
queueMicrotask(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
queueMicrotask(() => {
try {
let x = onRejected(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
});
}
if (this.state === "resolved") {
queueMicrotask(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
if (this.state === "rejected") {
queueMicrotask(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
});
}
});
return promise2;
};
function resolvePromise(promise2, x, resolve, reject) {
if (promise2 === x) {
reject(new TypeError("请避免Promise循环引用"));
}
let called;
if (x !== null && (typeof x === "object" || typeof x === "function")) {
// 可能是个对象或是函数
try {
let then = x.then;
if (typeof then === "function") {
then.call(
x,
(y) => {
if (called) return;
called = true;
// 递归调用,传入y若是Promise对象,继续循环
resolvePromise(promise2, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
}
);
} else {
resolve(x);
}
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
// 普通值结束递归
resolve(x);
}
}
class MyPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
constructor(executor) {
this.status = MyPromise.PENDING;
this.value = null;
this.callbacks = [];
executor(this.resolve.bind(this), this.reject.bind(this));
}
resolve(value) {
this.status = MyPromise.FULFILLED;
this.value = value;
setTimeout(() => {
this.callbacks.forEach((cb) => {
cb.onFulfilled(this.value);
});
});
}
reject(value) {
this.status = MyPromise.REJECTED;
this.value = value;
setTimeout(() => {
this.callbacks.forEach((cb) => {
cb.onRejected(this.value);
});
});
}
then(onFulfilled, onRejected) {
if (typeof onFulfilled !== "function") onFulfilled = (value) => value;
if (typeof onRejected !== "function") onRejected = (value) => value;
return new MyPromise((resolve, reject) => {
if (this.status === MyPromise.PENDING) {
this.callbacks.push({
onFulfilled: (value) => {
const res = onFulfilled(value);
this.resolvePromise(res, resolve, reject);
},
onRejected: (value) => {
const res = onFulfilled(value);
this.resolvePromise(res, resolve, reject);
},
});
}
if (this.status === MyPromise.FULFILLED) {
setTimeout(() => {
const res = onFulfilled(this.value);
this.resolvePromise(res, resolve, reject);
});
}
if (this.status === MyPromise.REJECTED) {
setTimeout(() => {
const res = onFulfilled(this.value);
this.resolvePromise(res, resolve, reject);
});
}
});
}
resolvePromise(res, resolve, reject) {
try {
// const res = onFulfilled(value);
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
} catch (error) {
reject(error);
}
}
}
TypeScript 实现,包含 Promise/A+ 测试,可作参考:
https://github.com/YieldRay/r-promise