// 记录Promise的三种状态
const PENDING = 'pending';
const FULFILLED = 'fulfilled';
const REJECTED = 'rejected';
class MyPromise {
/**
* 创建一个Promise
* @param {Function} executor 任务执行器,立即执行
*/
constructor(executor) {
this._state = PENDING; // 状态
this._value = undefined; // 数据
this._handlers = []; // 处理函数形成的队列
// Promise执行过程中,一旦报错直接reject
// 使用try...catch捕获错误
try {
// executor是调用Promise时传递的函数参数
// 属于同步执行代码,所以直接调用
executor(this._resolve.bind(this), this._reject.bind(this));
// 使用bind的原因:resolve改变当前promise实例的数据和状态,
// 使用了this(class在严格模式下执行,this会指向undefined)
// 所以使用bind改变this指向,指向当前Promise实例
} 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) {
// 放入任务队列的executor可能为undefined、123
// 为undefined的情况:then方法值传递了一个thenable事件处理函数,没有传递catchable
// 只负责将任务放入任务队列,不负责处理以上的情况,以上情况将在executor执行的时候处理
// 同时存入resolve和reject,根据相应的state执行resolve或reject
this._handlers.push({
executor,
state,
resolve,
reject,
});
}
/**
* 根据实际情况,执行队列
* 调用时机:
* 1.状态改变的时候(resolve和reject) --> _changState
* 2.const p = new Promsie((resolve, reject) => { resolve(1) });
* p.then((data) => { console.log(data) });
* 调用then的时候,状态已经改变
*/
_runHandlers() {
if (this._state === PENDING) {
// 目前任务仍在挂起
return;
}
while (this._handlers[0]) {
const handler = this._handlers[0];
this._runOneHandler(handler);
// 避免注册多个then方法后,先注册的处理函数在后注册then执行时再次执行
this._handlers.shift();
}
}
/**
* 处理一个handler
* @param {Object} handler
*/
_runOneHandler({ executor, state, resolve, reject }) {
runMicroTask(() => {
if (this._state !== state) {
// 状态不一致,不处理
return;
}
if (typeof executor !== 'function') {
// 传递后续处理并非一个函数
// then(() => {})只传递了一个函数,或者then(123)
// const pro1 = new Promise((resolve, reject) => {})
// const pro2 = pro1.then(() => {});
// 如果pro1失败了,pro2没有失败的处理
// pro1的状态是什么,pro2的状态就是什么
// 值穿透(状态穿透)
// resolve、reject是then返回的Promise的,由前一个Promise的状态决定调用
this._state === FULFILLED ? resolve(this._value) : reject(this._value);
return;
}
try {
const result = executor(this._value);
if (isPromise(result)) {
// thenable函数返回的是一个promise
// 那么then返回的promise的状态和thenable返回的promise的状态保持一致
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)不会立即执行,也不会立即加入到微任务队列
* then要做的事:将onFulfilled、onRejected放入任务队列
*/
then(onFulfilled, onRejected) {
// 没有立即把onFulfilled和onRejected放入任务队列的原因
// 如果立即加入任务队列,多次调用then,任务队列中有多个函数[fn1, fn2, ...fnn]
// 没有办法知道任务队列中的函数是成功之后执行还是失败之后执行
// 调用_pushHandler给函数标记状态并放入任务队列
// 返回一个新的Promise
return new MyPromise((resolve, reject) => {
// 同时传递resolve和reject
this._pushHandler(onFulfilled, FULFILLED, resolve, reject);
this._pushHandler(onRejected, REJECTED, resolve, reject);
// 调用then的时候,可能状态已经改变,所以需要调用一次
this._runHandlers(); // 执行队列
});
}
/**
* 仅处理失败的场景
* @param {Function} onRejected
*/
catch(onRejected) {
return this.then(null, onRejected);
}
/**
* 无论成功还是失败都会执行回调onSettled
* @param {Function} onSettled
*/
finally(onSettled) {
// finally就是一个特殊的then
// return this.then(onSettled, onSettled);
// 会导致前一个promise的值传递到onSettled
// data和reason是前一个promise的resolve的值或执行错误的原因
// onSettled如果执行报错,传递给then的onFulfilled或onRejected就会报错,finally返回的promise就会是rejected
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) {
// 改变状态_state和数据_value
this._changeState(FULFILLED, data);
}
/**
* 标记当前任务失败
* @param {any} reason 任务失败的相关数据
*/
_reject(reason) {
// 改变状态_state和数据_value
this._changeState(REJECTED, reason);
}
/**
* 返回一个已完成的Promise
* 特殊情况:
* 1. 传递的data本身就是ES6的Promise对象
* 2. 传递的data是PromiseLike(Promise A+),返回新的Promise,状态和其保持一致即可
* @param {any} data
*/
static resolve(data) {
if (data instanceof MyPromise) {
return data;
}
return new MyPromise((resolve, reject) => {
if (isPromise(data)) {
// data是PromiseLike
data.then(resolve, reject);
} else {
resolve(data);
}
});
}
/**
* 得到一个被拒绝的Promise
* @param {any}} reason
*/
static reject(reason) {
return new MyPromise((resolve, reject) => {
reject(reason);
});
}
/**
* 得到一个新的Promise
* 该Promise的状态取决于proms的执行
* proms是一个迭代器,包含多个Promise
* 全部Promise成功,则返回的Promise成功,数据为所有Promise成功的数据,并且顺序是按照传入的顺序排列
* 只要有一个Promise失败,则返回的Promise失败,原因是第一个失败的Promise的原因
* @param {iterator} proms
*/
static all(proms) {
return new MyPromise((resolve, reject) => {
try {
const results = [];
let count = 0; // Promise的总数
let fulfilledCount = 0; // 已完成的数量
for (const p of proms) { // 传递的proms可能是一个迭代器,迭代器不能使用for循环
// 迭代器不一定有length属性
// let i = count;
// count++;
let i = count++;
// 不直接使用p.then(data => result.push(data))
// 是因为没办法确定哪个promise先完成,就无法保准result是按顺序排列的
// 使用MyPromise.resolve是因为proms中传递的有可能不是promise
// 如果传递给resolve的是一个promise旧直接返回了
MyPromise.resolve(p).then((data) => {
fulfilledCount++;
results[i] = data;
if (fulfilledCount === count) {
// 当前是最后一个Promise完成了
resolve(results);
}
}, reject);
}
// 传递的proms数组是空数组,直接返回空数组
if (count === 0) {
resolve(results);
}
} catch (error) {
reject(error);
console.error(error);
}
});
}
/**
* 等待所有的Promise有结果之后
* 该方法返回的Promise完成
* 并且按照顺序将所有结果汇总(不管成功还是失败)
* @param {iterator} proms
*/
static allSettled(proms) {
const ps = [];
for (const p of proms) {
ps.push(
MyPromise.resolve(p).then(
(value) => ({
status: FULFILLED,
value,
}),
(reason) => ({
status: REJECTED,
reason,
})
)
);
}
return MyPromise.all(ps);
}
/**
* 返回的Promise与第一个有结果的一致
* @param {iterator} proms
*/
static race(proms) {
return new MyPromise((resolve, reject) => {
for (const p of proms) {
MyPromise.resolve(p).then(resolve, reject);
}
});
}
}
/**
* 判断一个数据是否是Promise对象
* @param {any} obj
* @returns
*/
function isPromise(obj) {
return !!(obj && typeof obj === 'object' && typeof obj.then === 'function');
}
/**
* 运行一个微队列任务
* 把传递的函数放到微队列中
* @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);
}
}
function delay(duration) {
return new Promise(resolve => {
setTimeout(resolve, duration)
});
};
const pro = new Promise((resolve, reject) => {
resolve(1);
// reject(1); // pro2也会是失败的
});
// 一般地,pro2的状态和pro完全一致,和finally的执行没有关系
// 但是finall执行中报错,pro2的状态会是rejected的
const pro2 = pro.finally((d) => {
console.log('finally', d); // finally undefined
// 返回结果是无效的,不会改不
return 123;
});