实现一个自定义promise 并通过Promise/A+测试
const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function MyPromise(executor) {
const self = this;
self.value = null;
self.error = null;
self.status = PENDING;
self.onFulfilledCallbacks = [];
self.onRejectedCallbacks = [];
function resolve(value) {
if (value instanceof MyPromise) {
return value.then(resolve, reject);
}
if (self.status === PENDING) {
self.status = FULFILLED;
self.value = value;
self.onFulfilledCallbacks.forEach((callback) => callback(self.value));
}
}
function reject(error) {
if (self.status === PENDING) {
self.status = REJECTED;
self.error = error;
self.onRejectedCallbacks.forEach((callback) => callback(self.error));
}
}
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
function resolvePromise(promise2, x, resolve, reject) {
//2.3.1规范,避免循环引用
if (promise2 === x) {
return reject(new TypeError('Circular reference'));
}
let called = false;
if (x != null && ((typeof x === 'object') || (typeof x === 'function'))) {
try {
// 是否是thenable对象(具有then方法的对象/函数)
//2.3.3.1 将 then 赋为 x.then
let then = x.then;
if (typeof then === 'function') {
//2.3.3.3 如果 then 是一个函数,以x为this调用then函数,且第一个参数是resolvePromise,第二个参数是rejectPromise
then.call(x, y => {
if (called) return;
called = true;
resolvePromise(promise2, y, resolve, reject);
}, error => {
if (called) return;
called = true;
reject(error);
})
} else {
//2.3.3.4 如果 then不是一个函数,则 以x为值fulfill promise。
resolve(x);
}
} catch (e) {
//2.3.3.2 如果在取x.then值时抛出了异常,则以这个异常做为原因将promise拒绝。
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
}
MyPromise.resolve = (val) => {
return new MyPromise((resolve) => {
resolve(val)
})
}
MyPromise.reject = (err) => {
return new MyPromise((resolve, reject) => {
reject(err)
})
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
const self = this;
let promise2;
onFulfilled = typeof onFulfilled === "function" ? onFulfilled : value => value;
onRejected = typeof onRejected === "function" ? onRejected : error => {
throw error
};
if (self.status === FULFILLED) {
return promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
let x = onFulfilled(self.value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
})
}
if (self.status === REJECTED) {
return promise2 = new MyPromise((resolve, reject) => {
setTimeout(() => {
try {
let x = onRejected(self.error);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
}, 0);
});
}
if (self.status === PENDING) {
return promise2 = new MyPromise((resolve, reject) => {
self.onFulfilledCallbacks.push((value) => {
setTimeout(()=>{
try {
let x = onFulfilled(value);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
self.onRejectedCallbacks.push((error) => {
setTimeout(()=>{
try {
let x = onRejected(error);
resolvePromise(promise2, x, resolve, reject);
} catch (e) {
reject(e);
}
})
});
});
}
}
MyPromise.prototype.catch = function (onRejected) {
return this.then(null, onRejected);
}
MyPromise.prototype.finally = function (onFinally) {
return this.then(
res => MyPromise.resolve(onFinally()).then(() => res),
err => MyPromise.resolve(onFinally()).then(() => { throw err; })
);
}
const isPromise = (x) => {
if (x !== null && (typeof x == 'object' || typeof x == 'function')) {
try {
const then = x.then;
return typeof then == 'function';
} catch (e) {
return false
}
} else {
return false
}
}
MyPromise.all = function (values) {
return new MyPromise((resolve, reject) => {
let arr = [];
let index = 0;
const dealResult = (val, i) => {
arr[i] = val;
index++;
if (index === values.length) {
resolve(arr)
}
}
for (let i = 0; i < values.length; i++) {
let item = values[i];
if (isPromise(item)) {
item.then(res => {
dealResult(res, i)
}, reject)
} else {
dealResult(item, i)
}
}
})
}
MyPromise.allSettled = function (values) {
return new MyPromise((resolve) => {
let arr = [];
let index = 0;
const dealResult = (val, i) => {
arr[i] = val;
index++;
if (index === values.length) {
resolve(arr)
}
}
for (let i = 0; i < values.length; i++) {
let item = values[i];
if (isPromise(item)) {
item.then(res => {
dealResult({
status: "fulfilled",
value: res
}, i)
}, (err) => {
dealResult({
status: "rejected",
reason: err
}, i)
})
} else {
dealResult({
status: "fulfilled",
value: item
}, i)
}
}
})
}
MyPromise.race = function (values) {
return new Promise(function (resolve, reject) {
for (let i = 0; i < values.length; i++) {
let item = values[i];
if (isPromise(item)) {
item.then(res => {
resolve(res)
}, reject)
} else {
resolve(item)
}
}
})
}
MyPromise.any = function (values) {
return new Promise(function (resolve, reject) {
const arr = [];
for (let i = 0; i < values.length; i++) {
let item = values[i];
if (isPromise(item)) {
item.then(res => {
resolve(res)
}, (err) => {
arr.push(err);
if (arr.length === values.length) {
reject(new AggregateError("All promises were rejected"))
}
})
} else {
resolve(item)
}
}
})
}
// 执行测试用例需要用到的代码
MyPromise.deferred = function () {
let defer = {};
defer.promise = new MyPromise((resolve, reject) => {
defer.resolve = resolve;
defer.reject = reject;
});
return defer;
}
try {
module.exports = MyPromise
} catch (e) {
}
Promise/A+测试
yarn add promises-aplus-tests
然后输入命令行进行测试
promises-aplus-tests MyPromise.js
结果:
872 passing (18s)