295 lines
7.2 KiB
JavaScript
295 lines
7.2 KiB
JavaScript
// 记录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;
|
||
}
|
||
// 下面这个判断是为了处理value为Promise的情况
|
||
// 这一段代码课程中没有涉及,特此注释说明
|
||
if (isPromise(value)) {
|
||
value.then(this._resolve.bind(this), this._reject.bind(this));
|
||
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);
|
||
}
|
||
|
||
/**
|
||
* 返回一个已完成的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.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) {
|
||
let i = count;
|
||
count++;
|
||
MyPromise.resolve(p).then((data) => {
|
||
fulfilledCount++;
|
||
results[i] = data;
|
||
if (fulfilledCount === count) {
|
||
// 当前是最后一个Promise完成了
|
||
resolve(results);
|
||
}
|
||
}, reject);
|
||
}
|
||
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);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
|