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? 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
我真的是太懒了。。。语言表达能力不行,不想写具体过程了,这里直接贴瓶子大佬的详解吧🤣原理都差不多的: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: