如何实现一个简单的 Promise
Issue 欢迎在 Gtihub Issue 中回答此问题: Issue 23
Author 回答者: shfshanyue
一个简单的 Promise
的粗糙实现,关键点在于
- 当
pending
时,thenable
函数由一个队列维护 - 当状态变为
resolved(fulfilled)
时,队列中所有thenable
函数执行 - 当
resolved
时,thenable
函数直接执行
rejected
状态同理
class Prom {
static resolve(value) {
if (value && value.then) {
return value;
}
return new Prom((resolve) => resolve(value));
}
constructor(fn) {
this.value = undefined;
this.reason = undefined;
this.status = "PENDING";
// 维护一个 resolve/pending 的函数队列
this.resolveFns = [];
this.rejectFns = [];
const resolve = (value) => {
// 注意此处的 setTimeout
setTimeout(() => {
this.status = "RESOLVED";
this.value = value;
this.resolveFns.forEach(({ fn, resolve: res, reject: rej }) =>
res(fn(value)),
);
});
};
const reject = (e) => {
setTimeout(() => {
this.status = "REJECTED";
this.reason = e;
this.rejectFns.forEach(({ fn, resolve: res, reject: rej }) =>
rej(fn(e)),
);
});
};
fn(resolve, reject);
}
then(fn) {
if (this.status === "RESOLVED") {
const result = fn(this.value);
// 需要返回一个 Promise
// 如果状态为 resolved,直接执行
return Prom.resolve(result);
}
if (this.status === "PENDING") {
// 也是返回一个 Promise
return new Prom((resolve, reject) => {
// 推进队列中,resolved 后统一执行
this.resolveFns.push({ fn, resolve, reject });
});
}
}
catch(fn) {
if (this.status === "REJECTED") {
const result = fn(this.value);
return Prom.resolve(result);
}
if (this.status === "PENDING") {
return new Prom((resolve, reject) => {
this.rejectFns.push({ fn, resolve, reject });
});
}
}
}
Prom.resolve(10)
.then((o) => o * 10)
.then((o) => o + 10)
.then((o) => {
console.log(o);
});
return new Prom((resolve, reject) => reject("Error")).catch((e) => {
console.log("Error", e);
});
Author 回答者: heretic-G
function MyPromise(executor) {
if (typeof executor !== "function") {
// throw new Error('Promise resolver 1 is not a function')
}
if (this instanceof MyPromise) {
// throw new Error(`${this} is not a promise`)
}
this.PromiseState = "pending";
this.PromiseFulfillReactions = [];
this.PromiseRejectReactions = [];
this.PromiseIsHandled = false;
this.AlreadyResolved = false;
let resolve = _Resolve(this);
let reject = _Reject(this);
try {
executor(resolve, reject);
} catch (e) {
reject(e);
}
}
MyPromise.prototype.then = function (onFulfilled, onRejected) {
let promise = this;
let capability = NewPromiseCapability();
return PerformPromiseThen(promise, onFulfilled, onRejected, capability);
};
function _Resolve(promise) {
return function __Resolve(resolution) {
if (promise.AlreadyResolved) {
return undefined;
}
promise.AlreadyResolved = true;
if (resolution === promise) {
return RejectPromise(promise, TypeError("is same"));
}
if (
(typeof resolution !== "function" && typeof resolution !== "object") ||
resolution === null
) {
return FulfillPromise(promise, resolution);
}
let then;
try {
then = resolution.then;
} catch (e) {
return RejectPromise(promise, e);
}
if (typeof then !== "function") {
return FulfillPromise(promise, resolution);
} else {
let job = NewPromiseResolveThenableJob(promise, resolution, then);
HostEnqueuePromiseJob(job);
}
return undefined;
};
}
function _Reject(promise) {
return function __Reject(reason) {
if (promise.AlreadyResolved) {
return undefined;
}
promise.AlreadyResolved = true;
RejectPromise(promise, reason);
};
}
function executor(resolve, reject) {
this.resolve = resolve;
this.reject = reject;
}
function NewPromiseCapability() {
let capability = {
resolve: undefined,
reject: undefined,
promise: undefined,
};
capability.promise = new MyPromise(executor.bind(capability));
return capability;
}
function PerformPromiseThen(
promise,
onFulfilled,
onRejected,
resultCapability,
) {
let fulfillReaction = {
Capability: resultCapability,
Type: "Fulfill",
Handler: onFulfilled,
};
let rejectReaction = {
Capability: resultCapability,
Type: "Reject",
Handler: onRejected,
};
if (promise.PromiseState === "pending") {
promise.PromiseFulfillReactions.push(fulfillReaction);
promise.PromiseRejectReactions.push(rejectReaction);
} else if (promise.PromiseState === "fulfilled") {
let resolution = promise.PromiseResult;
let job = NewPromiseReactionJob(fulfillReaction, resolution);
HostEnqueuePromiseJob(job);
} else {
if (!promise.PromiseIsHandled) {
}
let reason = promise.PromiseResult;
let job = NewPromiseReactionJob(rejectReaction, reason);
HostEnqueuePromiseJob(job);
}
promise.PromiseIsHandled = true;
if (!resultCapability) return undefined;
return resultCapability.promise;
}
function FulfillPromise(promise, resolution) {
if (promise.PromiseState !== "pending") {
return undefined;
}
let reactions = promise.PromiseFulfillReactions;
promise.PromiseResult = resolution;
promise.PromiseRejectReactions = [];
promise.PromiseFulfillReactions = [];
promise.PromiseState = "fulfilled";
TriggerPromiseReactions(reactions, resolution);
}
function RejectPromise(promise, reason) {
if (promise.PromiseState !== "pending") {
return undefined;
}
let reactions = promise.PromiseRejectReactions;
promise.PromiseResult = reason;
promise.PromiseRejectReactions = [];
promise.PromiseFulfillReactions = [];
promise.PromiseState = "rejected";
if (!promise.PromiseIsHandled) {
}
TriggerPromiseReactions(reactions, reason);
}
function TriggerPromiseReactions(reactions, argument) {
reactions.forEach((curr) => {
let job = NewPromiseReactionJob(curr, argument);
HostEnqueuePromiseJob(job);
});
}
function NewPromiseReactionJob(reaction, argument) {
return function () {
let capability = reaction.Capability;
let type = reaction.Type;
let handler = reaction.Handler;
let handlerResult;
let isError = false;
if (typeof handler !== "function") {
if (type === "Fulfill") {
handlerResult = argument;
} else {
isError = true;
handlerResult = argument;
}
} else {
try {
handlerResult = handler(argument);
} catch (e) {
isError = true;
handlerResult = e;
}
}
if (!capability) return undefined;
let status;
if (!isError) {
status = capability.resolve(handlerResult);
} else {
status = capability.reject(handlerResult);
}
return status;
};
}
function NewPromiseResolveThenableJob(promiseToResolve, thenable, then) {
return function () {
let resolve = _Resolve(promiseToResolve);
let reject = _Reject(promiseToResolve);
promiseToResolve.AlreadyResolved = false;
let result;
try {
result = then.call(thenable, resolve, reject);
} catch (e) {
return reject(e);
}
return result;
};
}
function HostEnqueuePromiseJob(job) {
setTimeout(job, 0);
}
MyPromise.deferred = function () {
let dfd = {};
dfd.promise = new MyPromise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = MyPromise;
Author 回答者: hsq777
一个简单的
Promise
的粗糙实现,关键点在于
- 当
pending
时,thenable
函数由一个队列维护- 当状态变为
resolved(fulfilled)
时,队列中所有thenable
函数执行- 当
resolved
时,thenable
函数直接执行
rejected
状态同理class Prom { static resolve(value) { if (value && value.then) { return value; } return new Prom((resolve) => resolve(value)); } constructor(fn) { this.value = undefined; this.reason = undefined; this.status = "PENDING"; // 维护一个 resolve/pending 的函数队列 this.resolveFns = []; this.rejectFns = []; const resolve = (value) => { // 注意此处的 setTimeout setTimeout(() => { this.status = "RESOLVED"; this.value = value; this.resolveFns.forEach(({ fn, resolve: res, reject: rej }) => res(fn(value)), ); }); }; const reject = (e) => { setTimeout(() => { this.status = "REJECTED"; this.reason = e; this.rejectFns.forEach(({ fn, resolve: res, reject: rej }) => rej(fn(e)), ); }); }; fn(resolve, reject); } then(fn) { if (this.status === "RESOLVED") { const result = fn(this.value); // 需要返回一个 Promise // 如果状态为 resolved,直接执行 return Prom.resolve(result); } if (this.status === "PENDING") { // 也是返回一个 Promise return new Prom((resolve, reject) => { // 推进队列中,resolved 后统一执行 this.resolveFns.push({ fn, resolve, reject }); }); } } catch(fn) { if (this.status === "REJECTED") { const result = fn(this.value); return Prom.resolve(result); } if (this.status === "PENDING") { return new Prom((resolve, reject) => { this.rejectFns.push({ fn, resolve, reject }); }); } } } Prom.resolve(10) .then((o) => o * 10) .then((o) => o + 10) .then((o) => { console.log(o); }); return new Prom((resolve, reject) => reject("Error")).catch((e) => { console.log("Error", e); });
catch里面应该是return Prom.reject(result)
吧
Author 回答者: hefeng6500
话不多说,看码!
// 1、基本架构:
// 状态
// then
// 执行器函数 executor
// 2、executor、resolve、reject
// 3、then 同步下调用
// 4、then 异步下调用
// 5、then 链式调用
// 返回 Promise
// then 函数递归返回常量结果,供下个 then 使用
// 考虑 then 成功的回调为 null 的情况
class Promise {
static PENDING = "pending";
static RESOLVED = "resolved";
static REJECTED = "rejected";
static resolve(value) {
return new Promise((resolve, reject) => {
resolve(value);
});
}
static reject(reason) {
return new Promise((resolve, reject) => {
reject(reason);
});
}
constructor(executor) {
this.state = Promise.PENDING;
this.value = undefined;
this.reason = undefined;
this.onResolvedCallbacks = [];
this.onRejectedCallbacks = [];
const resolve = (value) => {
if (value instanceof Promise) {
return value.then(resolve, reject);
}
if (this.state === Promise.PENDING) {
this.state = Promise.RESOLVED;
this.value = value;
this.onResolvedCallbacks.forEach((fn) => fn());
}
};
const reject = (reason) => {
this.state = Promise.REJECTED;
this.reason = reason;
this.onRejectedCallbacks.forEach((fn) => fn());
};
try {
executor(resolve, reject);
} catch (error) {
reject(error);
}
}
then(onFulfilled, onRejected) {
onFulfilled =
typeof onFulfilled === "function" ? onFulfilled : (value) => value;
onRejected =
typeof onRejected === "function"
? onRejected
: (reason) => {
throw reason;
};
let promise = new Promise((resolve, reject) => {
if (this.state === Promise.PENDING) {
this.onResolvedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
this.onRejectedCallbacks.push(() => {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
});
}
if (this.state === Promise.RESOLVED) {
setTimeout(() => {
try {
let x = onFulfilled(this.value);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
if (this.state === Promise.REJECTED) {
setTimeout(() => {
try {
let x = onRejected(this.reason);
resolvePromise(promise, x, resolve, reject);
} catch (error) {
reject(error);
}
});
}
});
return promise;
}
catch(onRejected) {
return this.then(null, onRejected);
}
all(arr) {
let count = 0;
let result = [];
return new Promise((resolve, reject) => {
for (let i = 0; i < arr.length; i++) {
Promise.resolve(arr[i])
.then((res) => {
result[i] = res;
if (++count === arr.length) {
resolve(res);
}
})
.catch((error) => {
reject(error);
});
}
});
}
race(arr) {
return new Promise((resolve, reject) => {
arr.forEach((item) => Promise.resolve(item).then(resolve, reject));
});
}
finally(callback) {
return this.then(
(value) => {
return Promise.resolve(callback()).then(() => value);
},
(reason) => {
return Promise.resolve(callback()).then(() => {
throw reason;
});
},
);
}
allSettled(arr) {
let count = 0;
let result = [];
return new Promise((resolve, reject) => {
const fn = (i, data) => {
if (count === arr.length) {
resolve(result);
}
result[i] = data;
count++;
};
for (let i = 0; i < arr.length; i++) {
Promise.resolve(arr[i])
.then((res) => {
fn(i, { status: "fulfilled", value: res });
})
.catch((error) => {
fn(i, { status: "rejected", reason: error });
});
}
});
}
// from Node Util.promisify
promisify(f) {
return function (...args) {
return new Promise((resolve, reject) => {
function callback(error, result) {
if (error) {
reject(error);
} else {
resolve(result);
}
}
args.push(callback);
f.call(this, ...args);
});
};
}
// from Node Util.promisifyAll
promisifyAll(obj) {
for (let key in obj) {
if (typeof obj[key] === "function") {
obj[key] = this.promisify(obj[key]);
}
}
}
}
function resolvePromise(promise, x, resolve, reject) {
// let promise = new Promise((resolve) => {
// resolve(1);
// }).then((res) => {
// return promise;
// });
if (x === promise) {
throw TypeError("循环引用");
}
if ((typeof x === "object" && x !== null) || typeof x === "function") {
let called;
try {
let then = x.then;
if (typeof then === "function") {
then.call(
x,
(y) => {
if (called) return;
called = true;
resolvePromise(promise, y, resolve, reject);
},
(r) => {
if (called) return;
called = true;
reject(r);
},
);
} else {
// x: { then: {} }
if (called) return;
called = true;
resolve(x);
}
} catch (error) {
if (called) return;
called = true;
reject(error);
}
} else {
// 返回了常量,直接 resolve
resolve(x);
}
}
const p = new Promise((resolve, reject) => {
reject(1);
});
p.catch((error) => {
console.log("error + ", error);
return error;
}).then((res) => {
console.log(res);
});
Promise.deferred = function () {
let dfd = {};
dfd.promise = new Promise((resolve, reject) => {
dfd.resolve = resolve;
dfd.reject = reject;
});
return dfd;
};
module.exports = Promise;
Author 回答者: Yu-Lxy
在作者代码基础上做了一些修改 基本功能够用了
class myPromise {
static PENDING = "pending";
static FULFILLED = "fulfilled";
static REJECTED = "rejected";
static resolve(value) {
if (value && value.then) {
return value;
}
return new myPromise((resolve) => resolve(value));
}
static reject(value) {
return new myPromise((_, reject) => reject(value));
}
constructor(fn) {
this.status = myPromise.PENDING;
this.result = null;
this.resFns = [];
this.rejFns = [];
const resolve = (value) => {
if (this.status === myPromise.PENDING) {
setTimeout(() => {
this.status = myPromise.FULFILLED;
this.result = value;
this.resFns.forEach(({ fn, resolve, reject }) => resolve(fn(value)));
});
}
};
const reject = (reason) => {
if (this.status === myPromise.PENDING) {
setTimeout(() => {
this.status = myPromise.REJECTED;
this.result = reason;
this.rejFns.forEach(({ fn, resolve, reject }) => reject(fn(reason)));
});
}
};
try {
fn(resolve, reject);
} catch (err) {
reject(err);
}
}
then(resFn, rejFn) {
resFn = typeof resFn === "function" ? resFn : (value) => value;
rejFn = typeof rejFn === "function" ? rejFn : (reason) => reason;
const _promise = {
[myPromise.PENDING]: () => {
return new myPromise((resolve, reject) => {
this.resFns.push({ fn: resFn, resolve, reject });
this.rejFns.push({ fn: rejFn, resolve, reject });
});
},
[myPromise.FULFILLED]: () => myPromise.resolve(resFn(this.result)),
[myPromise.REJECTED]: () => myPromise.reject(rejFn(this.result)),
}[this.status];
return _promise();
}
catch(fn) {
return this.then(undefined, fn);
}
finally(cb) {
return this.then(cb, cb);
}
}