We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
我真的是太懒了。。。语言表达能力不行,不想写具体过程了,这里直接贴瓶子大佬的详解吧🤣原理都差不多的:sisterAn/blog#13
代码并不是为了写一个 ES5 的pollyfill,所以使用了 ES6+ 语法(箭头函数、class声明、Symbol等)
/** * 检查目标是否为thenable对象 * 任何对象,只要有then方法,那么它就可以被作为 Promise 实例去处理(鸭子辩型),所以这里的 Xpromise 可以跟原生 Promise 相互调用使用: * Promise.resolve(123).then(() => XPromise.resolve(24)).then(v => console.log(v)) */ function isThenable(obj) { if (obj !== null && (typeof obj === 'object' || typeof obj === 'function') && typeof obj.then === 'function'){ return true; } return false; } function typeOf(obj) { return Object.prototype.toString.call(obj).toLowerCase().slice(8,-1); } /** * 决议程序!!! */ function resolutionProcedure(promise, x, resolve, reject) { if (promise === x) { reject(new TypeError('Chaining cycle detected for promise #<Promise>')); }else if(x instanceof XPromise) { x.then(resolve, reject); } else if (typeof x === 'object' && x !== null || typeof x === 'function') { try { const then = x.then; if (typeof then === 'function') { // 记录 resolvePromise 或 rejectPromise 是否被调用过(或者说记录then是否被调用过) // 如果 resolvePromise 和 rejectPromise 均被调用,或者被同一参数调用了多次,则优先采用首次调用并忽略剩下的调用 // 当然这里加不加也无所谓的,因为在XPromise构造函数里就限定了,它的状态只能变更一次,后面的直接无视 // 没加这个判断顶多就是做些无用功 let called = false; try { // 如果 then 是函数,将 x 作为函数的作用域 this 调用之。传递两个回调函数作为参数,第一个参数叫做 resolvePromise ,第二个参数叫做 rejectPromise then.call( x, function resolvePromise(y) { if (called) return; called = true; // 如果 resolvePromise 以值 y 为参数被调用,则运行 [[Resolve]](promise, y) resolutionProcedure(promise, y, resolve, reject); }, function rejectPromise(r){ if (called) return; called = true; reject(r); } ) } catch (e) { if (called) return; called = true; reject(e); } } else { // 如果 then 不是函数,以 x 为参数执行 promise resolve(x); } }catch(e){ // 如果取 x.then 的值时抛出错误 e ,则以 e 为据因拒绝 promise reject(e); return } } else { // 如果 x 不为对象或者函数,以 x 为参数执行 promise resolve(x); } } const defer = setTimeout; const PENDING = 'pending'; const FULFILLED = 'fulfilled'; const REJECTED = 'rejected'; const PROP_VALUE = Symbol('value'); const PROP_STATUS = Symbol('status'); const PROP_REASON = Symbol('reason'); const QUEUE_FULFILLED = Symbol('fulfilledQueue'); const QUEUE_REJECTED = Symbol('rejectedQueue'); class XPromise { [PROP_STATUS] = PENDING; [QUEUE_FULFILLED] = []; [QUEUE_REJECTED] = []; constructor(executor){ const type = typeof executor; if (type !== 'undefined' && type !== 'function') { throw new TypeError(`Promise resolver ${type} is not a function`); } const resolve = (value) => { if (this[PROP_STATUS] !== PENDING) return; this[PROP_VALUE] = value; this[PROP_STATUS] = FULFILLED; this[QUEUE_FULFILLED].forEach(func => func(value)); } const reject = (e) => { if (this[PROP_STATUS] !== PENDING) return; this[PROP_REASON] = e; this[PROP_STATUS] = REJECTED; this[QUEUE_REJECTED].forEach(func => func(e)); } try { if (executor) executor(resolve, reject); } catch(e) { reject(e); } } then(onFulfilled, onRejected) { if (typeof onFulfilled !== 'function') onFulfilled = function onFulfilled(v){return v}; if (typeof onRejected !== 'function') onRejected = function onRejected(e){throw e}; const self = this; const resolveByStatus = (resolve, reject) => { defer(function resolveDeferFunc(){ try { const x = onFulfilled(self[PROP_VALUE]); resolutionProcedure(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } const rejectByStatus = (resolve, reject) => { defer(function rejectDeferFunc(){ try { const x = onRejected(self[PROP_REASON]); resolutionProcedure(promise2, x, resolve, reject); } catch (e) { reject(e); } }); } const promise2 = new XPromise(function executor(resolve, reject){ switch (self[PROP_STATUS]) { case PENDING: self[QUEUE_FULFILLED].push(function fulfilledFn(){ resolveByStatus(resolve, reject); }); self[QUEUE_REJECTED].push(function rejectedFn(){ rejectByStatus(resolve, reject); }); break; case FULFILLED: resolveByStatus(resolve, reject); break; case REJECTED: rejectByStatus(resolve, reject); break; default: break } }); return promise2; } // Promise/A+ 规范并没有规定要实现对象的 catch,finally及resolve,reject,all...等静态方法, // 手写 Promise 实现 then 方法即可,其他一切都是在 constructor + then 的基础上实现的 // 这里为了学习需要,按照 MDN 列举的几个方法都撸了一遍 catch(onRejected) { return this.then(undefined, onRejected); } finally(onFinally) { // 与Promise.resolve(2).then(() => {}, () => {}) (resolved的结果为undefined)不同,Promise.resolve(2).finally(() => {}) resolved的结果为 2。 // 同样,Promise.reject(3).then(() => {}, () => {}) (resolved 的结果为undefined), Promise.reject(3).finally(() => {}) rejected 的结果为 3 // [注] 在finally回调中 throw(或返回被拒绝的 promise)将以 throw() 指定的原因拒绝新的promise. return this.then( value => { return XPromise.resolve(onFinally()).then(() => value); }, reason => { return XPromise.resolve(onFinally()).then(() => {throw reason}); } ); } static resolve(value) { // 如果是Promise实例,直接返回该对象 if (value instanceof XPromise) return value; // !!如果是thenable对象,用resolve、reject作为参数调用它的then方法 if (isThenable(value)) { return new XPromise((resolve, reject) => value.then(resolve, reject)); } return new XPromise(resolve => resolve(value)); } static reject(reason) { return new XPromise((_, reject) => reject(reason)); } static all(iterable) { return new XPromise(function allExecutor(resolve, reject){ const res = []; let count = 0; // 记录当前迭代的数据量 let resolvedCount = 0; function resolveRes(index, value) { res[index] = value; resolvedCount += 1; // console.log(resolvedCount, count, index, value); if (resolvedCount >= count) { resolve(res); } } // 任何可迭代对象都可以处理 for (const item of iterable) { count++; // 注意对thenable对象的处理!! // item instanceof XPromise 语句可以不用写,它肯定是thenable的,同时在XPromise.resolve会检查直接返回这个对象 (function(index){ if (item instanceof XPromise || isThenable(item)) { XPromise.resolve(item).then( value => resolveRes(index, value), reason => reject(reason), ); } else { resolveRes(index, item); } })(count-1) } if (count === 0) resolve([]); }); } static allSettled(iterable) { return new XPromise(function allSettledExecutor(resolve, reject){ const res = []; let count = 0; let resolvedCount = 0; function resolveRes(index, value) { res[index] = value; resolvedCount += 1; if (resolvedCount >= count) { resolve(res); } } for (const item of iterable) { count++; (function(index){ if (isThenable(item)) { XPromise.resolve(item).then( value => resolveRes(index, {status: FULFILLED, value}), reason => resolveRes(index, {status: REJECTED, reason}), ); } else { resolveRes(index, {status: FULFILLED, value: item}); } })(count-1); } if (count === 0) resolve([]); }); } static any(iterable) { return new XPromise(function anyExecutor(resolve, reject){ let count = 0; let resolvedCount = 0; const errors = []; function rejectRes(index, reason) { resolvedCount += 1; errors[index] = reason; if (resolvedCount >= count) { reject(new AggregateError(errors, 'All promises were rejected')); } } for (const item of iterable) { count++; (function(index){ if (isThenable(item)) { XPromise.resolve(item).then( value => resolve(value), reason => rejectRes(index, reason), ); } else { resolve(item); } })(count-1) } if (count === 0) reject(new AggregateError([], 'All promises were rejected')); }); } static race(iterable) { return new XPromise(function raceExecutor(resolve, reject){ for (const item of iterable) { if (isThenable(item)) { XPromise.resolve(item).then( value =>resolve(value), reason => reject(reason), ); } else { resolve(item); } } }); } }
The text was updated successfully, but these errors were encountered:
Sorry, something went wrong.
No branches or pull requests
我真的是太懒了。。。语言表达能力不行,不想写具体过程了,这里直接贴瓶子大佬的详解吧🤣原理都差不多的:sisterAn/blog#13
完整实现
参考文献
The text was updated successfully, but these errors were encountered: