const PENDING = "pending";
const FULFILLED = "fulfilled";
const REJECTED = "rejected";
function asyncExecFun(fn) {
setTimeout(() => fn(), 0);
}
function resolvePromise(promise, res, resolve, reject) {
if (promise === res) {
reject(new TypeError("Chaining cycle detected for promise #<MyPromise>"));
return;
}
if (res instanceof MyPromise) {
res.then(resolve, reject);
} else {
resolve(res);
}
}
class MyPromise {
status = PENDING;
value = undefined;
reason = undefined;
successCallbacks = [];
failCallbacks = [];
constructor(exector) {
try {
exector(
(value) => asyncExecFun(() => this.resolve(value)),
(reason) => asyncExecFun(() => this.reject(reason))
);
} catch (e) {
this.reject(e)
}
}
resolve(value) {
if (this.status !== PENDING) return;
this.value = value;
this.status = FULFILLED;
while (this.successCallbacks.length) this.successCallbacks.shift()();
}
reject(reason) {
if (this.status !== PENDING) return;
this.reason = reason;
this.status = REJECTED;
if(!this.failCallbacks.length){
throw '(in MyPromise)'
}
while (this.failCallbacks.length) this.failCallbacks.shift()();
}
then(successCallback, failCallback) {
successCallback =
typeof successCallback == "function" ? successCallback : (v) => v;
failCallback =
typeof failCallback == "function"
? failCallback
: (reason) => {
throw reason;
};
let promise = new MyPromise((resolve, reject) => {
const execFun = (fn, val) => {
try {
let res = fn(val);
resolvePromise(promise, res, resolve, reject);
} catch (e) {
reject(e);
}
};
const execSuccessCallback = () => execFun(successCallback, this.value);
const execFailCallback = () => execFun(failCallback, this.reason);
if (this.status === PENDING) {
this.successCallbacks.push(execSuccessCallback);
this.failCallbacks.push(execFailCallback);
return;
}
asyncExecFun(() => {
if (this.status === FULFILLED) {
execSuccessCallback();
} else if (this.status === REJECTED) {
execFailCallback();
}
});
});
return promise;
}
catch(failCallback) {
return this.then(undefined, failCallback);
}
finally(callback) {
return this.then(
// 穿透正常值
(value) => MyPromise.resolve(callback()).then(() => value),
(reason) =>
MyPromise.resolve(callback()).then(() => {
throw reason;
})
);
}
static resolve(value) {
if (value instanceof MyPromise) return value;
return new MyPromise((resolve) => resolve(value));
}
static reject(reason) {
if (reason instanceof MyPromise) return reason;
return new MyPromise((resolve, reject) => reject(reason));
}
static all(array) {
let result = [];
let len = array.length;
let promise = new MyPromise((resolve, reject) => {
let index = 0;
function addData(key, data) {
result[key] = data;
index++;
if (index == len) {
resolve(result);
}
}
for (let i = 0; i < len; i++) {
let curr = array[i];
if (curr instanceof MyPromise) {
curr.then((value) => addData(i, value), reject);
} else {
addData(i, curr);
}
}
});
return promise;
}
static race(array) {
let promise = new MyPromise((resolve, reject) => {
for (let i = 0; i < array.length; i++) {
let curr = array[i];
if (curr instanceof MyPromise) {
curr.then(resolve, reject);
} else {
resolve(curr);
}
}
});
return promise;
}
}