手写Promise
1. 个人理解
感觉手写Promise ,实际上是对发布订阅模式 及闭包 的一种应用。
2. 话不多说,直接撸
按照文档注释,与原生一一对比。场景可能没有覆盖全面,大致理解手写Promise的思想、原理即可。另Promise.allSettle 与Promise.any 方法没有写,原因是用的比较少…不过其原理大同小异,hah…
const CachePremitivePromise = Promise;
(function() {
function defineNotEnumrableProperty(obj, key, value) {
Object.defineProperty(obj, key, {
value,
enumerable: false,
writable: true
})
}
const cacheCbksMap = new Map();
function generateCacheCbksZone(inst) {
if (!cacheCbksMap.has(inst)) {
cacheCbksMap.set(inst, {
resolvedCbks: [],
rejectedCbks: []
})
}
}
function destoryCacheCbksZone(inst) {
if (cacheCbksMap.has(inst)) {
cacheCbksMap.delete(inst);
}
}
const STATE = {
PENDING: 'pending',
RESOLVED: 'resolved',
REJECTED: 'rejected'
};
function Promise(excutor) {
generateCacheCbksZone(this);
defineNotEnumrableProperty(this, '[[PromiseState]]', STATE.PENDING);
defineNotEnumrableProperty(this, '[[PromiseResult]]', undefined);
function resolve(result) {
if (this['[[PromiseState]]'] === STATE.PENDING) {
this['[[PromiseState]]'] = STATE.RESOLVED;
this['[[PromiseResult]]'] = result;
setTimeout(() => {
cacheCbksMap.get(this).resolvedCbks.forEach(fn => result = fn(result))
destoryCacheCbksZone(this);
})
}
}
function reject(reason) {
if (this['[[PromiseState]]'] === STATE.PENDING) {
this['[[PromiseState]]'] = STATE.REJECTED;
this['[[PromiseResult]]'] = reason;
setTimeout(() => {
const rejectedCbks = cacheCbksMap.get(this).rejectedCbks;
if (!rejectedCbks.length) {
throw new Error(reason);
}
rejectedCbks.forEach(fn => {
fn(reason);
})
destoryCacheCbksZone(this);
})
}
}
try {
excutor(resolve.bind(this), reject.bind(this));
} catch(e) {
reject.call(this, e);
}
}
Promise.resolve = function _resolve(result) {
return new Promise(resolve => resolve(result))
}
Promise.reject = function _reject(result) {
return new Promise((resolve, reject) => reject(result))
}
Promise.all = function _all(pArray) {
return new Promise((resolve, reject) => {
const resArray = [];
let completedCount = 0;
pArray.forEach((p, i) => {
p.then(
result => {
resArray[i] = result;
completedCount += 1;
if (resArray.length === completedCount) {
resolve(resArray);
}
},
reason => reject(reason)
)
})
})
}
Promise.race = function _race(pArray) {
return new Promise((resolve, reject) => {
pArray.forEach((p, i) => p.then(result => resolve(result), reason => reject(reason)))
})
}
const CachePromise = Promise;
{
function Promise() {
defineNotEnumrableProperty(this, 'then', function _then() {
const [onResolved, onRejected] = arguments;
return new CachePromise((resolve, reject) => {
const { resolvedCbks, rejectedCbks } = cacheCbksMap.get(this);
if (onResolved) {
resolvedCbks.push(onResolved, resolve);
}
if (onRejected) {
rejectedCbks.push(onRejected, () => resolve());
} else {
rejectedCbks.push(reject);
}
})
})
defineNotEnumrableProperty(this, 'catch', function _catch() {
const onCatch = arguments[0];
const self = this;
return new CachePromise((resolve, reject) => {
if (onCatch && cacheCbksMap.has(self)) {
cacheCbksMap.get(self).rejectedCbks.push(onCatch, () => resolve());
}
})
})
defineNotEnumrableProperty(this, 'finally', function _finally() {
const onFinally = arguments[0];
const self = this;
return new CachePromise((resolve, reject) => {
if (onFinally && cacheCbksMap.has(self)) {
const { resolvedCbks, rejectedCbks } = cacheCbksMap.get(self);
resolvedCbks.push(() => onFinally(), () => resolve());
rejectedCbks.push(() => onFinally(), reject);
}
})
})
}
CachePromise.prototype = new Promise();
defineNotEnumrableProperty(CachePromise.prototype, 'constructor', Promise);
}
Promise = CachePromise;
{
const p = Promise.resolve('自定义 resolved')
.then(
res => console.log('自定义 res-1111', res),
err => console.log('自定义 err-1111', err)
)
.finally(
err => console.log('自定义 finally', err),
);
console.log('自定义 finally', p);
}
{
const p = Promise.resolve('原生 resolved')
.then(
res => console.log('原生 res-1111', res),
err => console.log('原生 err-1111', err)
)
.finally(
err => console.log('原生 finally', err),
);
console.log('原生 finally', p);
}
})()
|