New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
【Q022】如何实现一个简单的 Promise #23
Comments
一个简单的
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)
}) |
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 |
catch里面应该是 |
话不多说,看码! // 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; |
在作者代码基础上做了一些修改 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)
}
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
No description provided.
The text was updated successfully, but these errors were encountered: