手写Promise(构造函数)
const PENDING_STATE = "pending";
const FULFILLED_STATE = "fulfilled";
const REJECTED_STATE = "rejected";
const isFunction = function (fn) {
return typeof fn === "function";
};
const isObject = function (value) {
return value && typeof value === "object";
};
function MyPromise(fn) {
if (!this || this.constructor !== MyPromise) {
throw new TypeError("Promise must be called with new");
}
if (!isFunction(fn)) {
throw new TypeError("Promise constructor's argument must be a function");
}
this.state = PENDING_STATE;
this.value = void 0;
this.onFulfilledCallbacks = []
this.onRejectedCallbacks = []
const resolve = (value) => {
resolutionProcedure(this, value)
}
const resolutionProcedure = function (promise, v) {
if (v === promise) {
return reject(new TypeError("Promise can not resolved with it self"))
}
if (v instanceof MyPromise) {
return v.then(resolve, reject)
}
if (isObject(v) || isFunction(v)) {
let called = false
try {
let then = v.then
if (isFunction(then)) {
then.call(
v,
(y) => {
if (called) {
return
}
called = true
resolutionProcedure(promise, y)
},
(error) => {
if (called) {
return
}
called = true
reject(error);
}
)
return
}
} catch (error) {
if (called) {
return;
}
called = true;
reject(error);
}
}
if (promise.state === PENDING_STATE) {
promise.state = FULFILLED_STATE
promise.value = v
promise.onFulfilledCallbacks.forEach((callback) => callback())
}
}
const reject = (reason) => {
if (this.state === PENDING_STATE) {
this.state = REJECTED_STATE
this.value = reason
this.onRejectedCallbacks.forEach((callback) => callback())
}
}
try {
fn(resolve, reject);
} catch (error) {
reject(error);
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
onFulfilled = isFunction(onFulfilled) ? onFulfilled : (value) => value
onRejected = isFunction(onRejected) ? onRejected : (error) => { throw error }
let newPromise = new MyPromise((resolve, reject) => {
let wrapOnFulfilled = () => {
setTimeout(() => {
try {
let v = onFulfilled(this.value)
resolve(v)
} catch (error) {
reject(error)
}
}, 0)
}
let wrapOnRejected = () => {
setTimeout(() => {
try {
let v = onRejected(this.value)
resolve(v)
} catch (error) {
reject(error)
}
}, 0)
}
if (this.state === FULFILLED_STATE) {
wrapOnFulfilled()
} else if (this.state === REJECTED_STATE) {
wrapOnRejected()
} else {
this.onFulfilledCallbacks.push(wrapOnFulfilled);
this.onRejectedCallbacks.push(wrapOnRejected);
}
})
return newPromise
}
MyPromise.prototype.catch = function (callback) {
return this.then(null, callback);
};
MyPromise.prototype.finally = function (callback) {
return this.then(
(data) => {
callback();
return data;
},
(error) => {
callback();
throw error;
}
);
};
MyPromise.resolve = function (value) {
return value instanceof MyPromise
? value
: new MyPromise((resolve) => resolve(value));
};
MyPromise.reject = function (reason) {
return new MyPromise((resolve, reject) => reject(reason));
};
MyPromise.race = function (promises) {
return new MyPromise((resolve, reject) => {
promises.forEach((promise) => {
MyPromise.resolve(promise).then(resolve, reject);
});
});
};
MyPromise.all = function (promises) {
return new MyPromise((resolve, reject) => {
if (!promises.length) {
resolve([]);
}
let result = [];
let resolvedPro = 0;
for (let index = 0, length = promises.length; index < length; index++) {
MyPromise.resolve(promises[index]).then(
(data) => {
result[index] = data;
if (++resolvedPro === length) {
resolve(result);
}
},
(error) => {
reject(error);
}
);
}
});
};
MyPromise.allSettled = function (promises) {
return new MyPromise((resolve, reject) => {
if (!promises.length) {
resolve([]);
}
let result = [];
let resolvedPro = 0;
for (let index = 0, length = promises.length; index < length; index++) {
MyPromise.resolve(promises[index])
.then((data) => {
result[index] = {
status: FULFILLED_STATE,
value: data,
};
if (++resolvedPro === length) {
resolve(result);
}
})
.catch((error) => {
result[index] = {
status: REJECTED_STATE,
reason: error,
};
if (++resolvedPro === length) {
resolve(result);
}
});
}
});
};
module.exports = MyPromise;