Promise A+ 规范实现完整版
本文正在参加「金石计划」
原文出自:圆圆01
之前 promise 手写过很多次,也没有写过一篇完整的,今天学习大佬跟着写一篇完整的promise
先看成果,能通过所有的测试用例
type AllSettledType = {
status: "fulfilled" | "rejected",
value: any
}
// myPromise A+
class myPromise {
private PENDING = "pending"
private FULFILLED = "fullfilled"
private REJECTED = "rejected"
private promiseState: string
private promiseResult: any
private onFulfilledCallbacks: Function[]
private onRejectedCallbacks: Function[]
constructor(executor: (arg0: (res: any) => void, arg1: (err: any) => void) => void) {
this.promiseState = this.PENDING
this.promiseResult = null
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const _resolve = (result: any) => {
if (this.promiseState === this.PENDING) {
this.promiseState = this.FULFILLED
this.promiseResult = result
this.onFulfilledCallbacks.forEach(callback => callback(result))
}
}
const _reject = (err: any) => {
if (this.promiseState === this.PENDING) {
this.promiseState = this.REJECTED
this.promiseResult = err
this.onRejectedCallbacks.forEach(callback => callback(err))
}
}
try {
executor(_resolve, _reject)
} catch (error) {
_reject(error)
}
}
then = (onfulfilled?: ((value: unknown) => unknown) | null | undefined, onrejected?: ((reason: any) => void | PromiseLike<void>) | null | undefined) => {
let promise = new myPromise((resolve, reject) => {
if (this.promiseState === this.FULFILLED) {
setTimeout(() => {
try {
if (typeof onfulfilled !== 'function') {
resolve(this.promiseResult);
} else {
let x = onfulfilled(this.promiseResult);
resolvePromise(promise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
} else if (this.promiseState === this.REJECTED) {
setTimeout(() => {
try {
if (typeof onrejected !== 'function') {
reject(this.promiseResult);
} else {
let x = onrejected(this.promiseResult);
resolvePromise(promise, x, resolve, reject);
}
} catch (e) {
reject(e)
}
});
} else if (this.promiseState === this.PENDING) {
this.onFulfilledCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof onfulfilled !== 'function') {
resolve(this.promiseResult);
} else {
let x = onfulfilled(this.promiseResult);
resolvePromise(promise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
if (typeof onrejected !== 'function') {
reject(this.promiseResult);
} else {
let x = onrejected(this.promiseResult);
resolvePromise(promise, x, resolve, reject);
}
} catch (e) {
reject(e);
}
});
});
}
})
return promise
}
catch = (onrejected: ((reason: any) => void | PromiseLike<void>) | null | undefined) => {
this.then(undefined, onrejected)
}
finally = (callback: (() => void) | null | undefined) => {
return this.then(callback, callback)
}
static resolve = (value: any) => {
if (value instanceof myPromise) {
return value
} else if (value instanceof Object && "then" in value) {
return new myPromise((resolve, reject) => {
value.then(resolve, reject)
})
}
return new myPromise((resolve) => {
resolve(value)
})
}
static reject = (err: any) => {
return new myPromise((resolve, reject) => {
reject(err)
})
}
// myPromise.all() 接受一个 promise 的 iterable 类型,Array ,Map , Set 都属于 ES6的 iterable 类型
static all = (promises: unknown[]) => {
return new myPromise((resolve, reject) => {
if (Array.isArray(promises)) {
let result: any = []
let count = 0
if (promises.length === 0) {
return resolve(promises)
}
promises.forEach((item, index) => {
myPromise.resolve(item).then(res => {
result[index] = res
count++
count === promises.length && resolve(result)
}, err => {
reject(err)
})
})
} else {
return reject(new TypeError("argument is not iterable"))
}
})
}
static allSettled = (promises: unknown[]) => {
return new myPromise((resolve, reject) => {
if (Array.isArray(promises)) {
let result: AllSettledType[] = []
let count = 0
if (promises.length === 0) return resolve(promises)
promises.forEach((item, index) => {
myPromise.resolve(item).then(res => {
result[index] = {
status: "fulfilled",
value: res
}
count++
count === promises.length && resolve(result)
}, err => {
result[index] = {
status: "rejected",
value: err
}
count === promises.length && resolve(result)
})
})
} else {
return reject(new TypeError("argument is not iterable"))
}
})
}
static any = (promises: unknown[]) => {
return new myPromise((resolve, reject) => {
if (Array.isArray(promises)) {
let errors: unknown[] = []
let count = 0
if (promises.length === 0) return reject(new Error('All promises were rejected'));
promises.forEach((item, index) => {
myPromise.resolve(item).then(res => {
resolve(res)
}, err => {
count++
errors.push(err)
count === promises.length && reject(new Error('All promises were rejected'))
})
})
} else {
return reject(new TypeError("arguments is not iterable"))
}
})
}
static race = (promises: unknown[]) => {
return new myPromise((resolve, reject) => {
if (Array.isArray(promises)) {
promises.forEach((item, index) => {
myPromise.resolve(item).then(resolve, reject)
})
} else {
return reject(new TypeError("arguments is not iterable"))
}
})
}
}
function resolvePromise(promise: myPromise, x: any, resolve: Function, reject: (reason: any) => void) {
// 循环引用
if (x === promise) {
throw new TypeError('Chaining cycle detected for promise');
}
// 如果 x 是 myPromise , 则 promise 接受 x 的状态,继续执行 x
if (x instanceof myPromise) {
x.then(res => {
resolvePromise(promise, res, resolve, reject)
}, reject);
} else if (x !== null && ((typeof x === 'object' || (typeof x === 'function')))) {
try {
var then = x.then;
} catch (e) {
return reject(e);
}
if (typeof then === 'function') {
let called = false;
try {
then.call(
x,
(y: any) => {
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject);
},
(r: any) => {
if (called) return;
called = true;
reject(r);
}
)
} catch (e) {
if (called) return;
called = true;
reject(e);
}
} else {
resolve(x);
}
} else {
return resolve(x);
}
}