遵循Promises/A+规范实现自定义Promise(期约)
该Promise类实现遵循Promises/A+规范,实现了then
、catch
、finally
的链式调用以及all
、allSettled
、race
、any
静态方法。
实现
class $Promise$ {
constructor(executor) {
// 初始化状态为pending
this.status = 'pending';
// 初始化成功的值为undefined
this.value = undefined;
// 初始化失败的原因为undefined
this.reason = undefined;
// 初始化成功处理函数队列
this.onFulfilledCallbacks = [];
// 初始化失败处理函数队列
this.onRejectedCallbacks = [];
// 定义resolve方法
const resolve = (value) => {
// 只有在pending状态才能更改状态和值
if (this.status === 'pending') {
// 如果是一个promise或者是一个类promise就在其then方法中调用
// if(value instanceof $Promise$ || (value && typeof value.then === 'function')) {
// value.then(resolve, reject);
// return;
// }
this.status = 'fulfilled';
this.value = value;
// 执行所有成功处理函数
this.onFulfilledCallbacks.forEach((callback) => callback());
}
};
// 定义reject方法
const reject = (reason) => {
// 只有在pending状态才能更改状态和原因
if (this.status === 'pending') {
this.status = 'rejected';
this.reason = reason;
// 执行所有失败处理函数
this.onRejectedCallbacks.forEach((callback) => callback());
}
};
// 立即执行执行器函数
try {
executor(resolve, reject);
} catch (error) {
// 如果执行器函数抛出异常,将Promise状态更改为rejected
reject(error);
}
}
then(onFulfilled, onRejected) {
// 如果不传处理函数,则使用默认处理函数
onFulfilled =
typeof onFulfilled === 'function' ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === 'function'
? onRejected
: (reason) => {
throw reason;
};
// 创建一个新的Promise实例,称为promise2
const promise2 = new $Promise$((resolve, reject) => {
if (this.status === 'fulfilled') {
// 使用queueMicrotask保证异步调用
queueMicrotask(() => {
try {
// 调用onFulfilled,并获取返回值
const x = onFulfilled(this.value);
// 使用返回值x和新的Promise实例promise2来处理resolve和reject
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果处理函数抛出异常,则将promise2状态更改为rejected
reject(error);
}
});
} else if (this.status === 'rejected') {
// 使用queueMicrotask保证异步调用
queueMicrotask(() => {
try {
// 调用onRejected,并获取返回值
const x = onRejected(this.reason);
// 使用返回值x和新的Promise实例promise2来处理resolve和reject
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果处理函数抛出异常,则将promise2状态更改为rejected
reject(error);
}
});
} else if (this.status === 'pending') {
// 如果当前Promise状态仍为pending,将处理函数加入相应的队列中
this.onFulfilledCallbacks.push(() => {
// 使用queueMicrotask保证异步调用
queueMicrotask(() => {
try {
// 调用onFulfilled,并获取返回值
const x = onFulfilled(this.value);
// 使用返回值x和新的Promise实例promise2来处理resolve和reject
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果处理函数抛出异常,则将promise2状态更改为rejected
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
// 使用queueMicrotask保证异步调用
queueMicrotask(() => {
try {
// 调用onRejected,并获取返回值
const x = onRejected(this.reason);
// 使用返回值x和新的Promise实例promise2来处理resolve和reject
resolvePromise(promise2, x, resolve, reject);
} catch (error) {
// 如果处理函数抛出异常,则将promise2状态更改为rejected
reject(error);
}
});
});
}
});
// 返回新的Promise实例,以便链式调用
return promise2;
}
catch(onRejected) {
// 调用then方法,仅传入失败处理函数
return this.then(null, onRejected);
}
finally(callback) {
// 调用then方法,传入两个相同的处理函数
return this.then(
(value) => {
// 创建一个新的Promise实例,确保异步执行callback
return $Promise$.resolve(callback()).then(() => value);
},
(reason) => {
// 创建一个新的Promise实例,确保异步执行callback
return $Promise$.resolve(callback()).then(() => {
throw reason;
});
}
);
}
static resolve(value) {
if (value instanceof $Promise$) {
return value;
}
return new $Promise$((resolve, reject) => {
resolve(value);
});
}
static reject(reason) {
return new $Promise$((resolve, reject) => {
reject(reason);
});
}
static all(promises) {
return new $Promise$((resolve, reject) => {
const result = [];
let resolvedCount = 0;
promises.forEach((promise, index) => {
$Promise$.resolve(promise).then(
(value) => {
result[index] = value;
resolvedCount++;
if (resolvedCount === promises.length) {
resolve(result);
}
},
(reason) => {
reject(reason);
}
);
});
});
}
static race(promises) {
return new $Promise$((resolve, reject) => {
promises.forEach((promise) => {
$Promise$.resolve(promise).then(
(value) => {
resolve(value);
},
(reason) => {
reject(reason);
}
);
});
});
}
static allSettled(promises) {
return new $Promise$((resolve, reject) => {
const result = [];
let settledCount = 0;
promises.forEach((promise, index) => {
$Promise$.resolve(promise).then(
(value) => {
result[index] = { status: 'fulfilled', value };
settledCount++;
if (settledCount === promises.length) {
resolve(result);
}
},
(reason) => {
result[index] = { status: 'rejected', reason };
settledCount++;
if (settledCount === promises.length) {
resolve(result);
}
}
);
});
});
}
static any(promises) {
return new $Promise$((resolve, reject) => {
const errors = [];
let rejectedCount = 0;
promises.forEach((promise, index) => {
$Promise$.resolve(promise).then(
(value) => {
resolve(value);
},
(reason) => {
errors[index] = reason;
rejectedCount++;
if (rejectedCount === promises.length) {
reject(new AggregateError(errors, 'All promises were rejected'));
}
}
);
});
});
}
}
function resolvePromise(promise2, x, resolve, reject) {
// 1. 如果 promise2 和 x 相同,抛出 TypeError
if (promise2 === x) {
return reject(new TypeError('Chaining cycle detected for promise'));
}
// 标记是否已调用,防止多次调用
let called = false;
// 2. 如果 x 是 $Promise$ 实例
if (x instanceof $Promise$) {
// 根据 x 的状态调用 resolve 或 reject
x.then(
(y) => {
resolvePromise(promise2, y, resolve, reject);
},
(reason) => {
reject(reason);
}
);
} else if (x !== null && (typeof x === 'object' || typeof x === 'function')) {
// 3. 如果 x 是对象或函数
try {
// 获取 x 的 then 方法
const then = x.then;
if (typeof then === 'function') {
// 如果 then 是函数
// 使用 x 作为上下文调用 then 方法
then.call(
x,
(y) => {
// 成功回调
if (called) return; // 如果已经调用过,直接返回
called = true;
// 递归处理 y
resolvePromise(promise2, y, resolve, reject);
},
(reason) => {
// 失败回调
if (called) return; // 如果已经调用过,直接返回
called = true;
reject(reason);
}
);
} else {
// 如果 then 不是函数
// 直接调用 resolve
resolve(x);
}
} catch (error) {
// 如果获取或调用 then 方法抛出异常
if (called) return; // 如果已经调用过,直接返回
called = true;
reject(error);
}
} else {
// 4. 如果 x 不是对象或函数
// 直接调用 resolve
resolve(x);
}
}
module.exports = $Promise$;
使用promises-aplus-tests
套件测试合规性

image.png
测试代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Document</title>
</head>
<body>
<script src="./index.js"></script>
<script>
//pending promise0
const promise = new PromisePolyfill((resolve, reject) => {
//步骤1 执行reject函数 将清空函数队列的任务排入微任务队列,返回了pending状态的promise
reject('reject');
resolve('resolve');
})
//步骤2 执行同步代码then1 将回调函数排入promise函数数组,返回pending状态的promise1
//pending promise1
promise.then(
(res) => {
//步骤6 同步代码执行完毕 开始执行promise回调函数,因为此时为reject,所以该函数不会执行,
//又因为没有传onRejected函数所以Promise内部准备执行onReject函数时,会直接抛出错误,然后被reject掉,理由会传到下一个then的第二个函数的参数
console.log('onFulfilled被调用',res);
return 'aaa'
}
//步骤3 执行同步代码then2 将回调函数排入promise1函数数组,返回pending状态的promise2
//pending promise2
).then(res => {
//步骤7,同样的,又因为没有传onRejected函数所以Promise内部准备执行onReject函数时,会直接抛出错误,然后被reject掉,理由会传到下一个then的第二个函数的参数
console.log('onFulfilled被调用1',res);
return 'bbb'
//步骤4 执行同步代码catch2 将回调函数排入promise2函数数组,返回pending状态的promise3
//pending promise3
}).catch(err => {
//步骤8,其实这个catch也是调用then,但是这个then把onRejected函数传入了,所以catch会再次捕获到上面传的错误
console.log('catch',err);
return 'bbb'
//步骤5 执行同步代码then3 将回调函数排入promise3函数数组,返回pending状态的promise4
//pending promise4
}).then(res => {
console.log('catch后面的then,'+res);
});
setTimeout(() => {
console.log(promise);
promise.then(res => {
console.log('setTimeout里面的then',res);
}).catch(err => {
console.log('setTimeout里面的catch',err);
})
},1000)
PromisePolyfill.resolve('PromisePolyfill.resolve').then(res => {
console.log(res);
})
PromisePolyfill.reject('PromisePolyfill.reject').then(res => {
console.log(res);
}).catch(err => {
console.log(err);
})
//当同步任务(宏任务)都执行完 微任务队列将开始执行
</script>
</body>
</html>