PromiseA+实现(跑通872用例)Cloudprg2024/07/14 06:37:51阅读9分钟

Promise是什么?

处理异步函数的状态机,拥有链式调用、错误捕获、状态不可逆等特性。为了解决地狱回调而设计的解决方案

A+规范概括

官方中文链接

初始化

  • 初始化 status, value ,reason , fullfilledQueue,rejectedQueue值
  • 接收一个fn,接收resolve,reject函数作为参数
  • 内部实现resovle,reject时,判断status是否为Pending,若是,则转为指定状态,并更新当前value/reason,遍历回调。

then的实现

  • 首先判断接收的参数是否为函数类型,不是则转函数v=>v,当然onReject需要抛出值r=>{throw r};
  • 需要返回一个promise,这个promise的resolve/reject由状态、onFullFilled/onRejected计算结果来决定。

状态之分

  • fullfiled/rejected: 计算结果x,再将x传入resolvePromise作结果解析
  • pending:两个队列推入 上一步的逻辑。

resovlePromise

  • 这一步主要是处理 x和then中返回的promise是否相同,相同则报错(循环引用报错)。
  • 判断x的类型,普通类型则直接resovle解决
  • 若是object / function,若存在then,试图try&catch执行,根据then结果递归调用resovlePromise。 (注意,这里可能同时触发 resovle,reject。因此需要用标识符 called来防止多处调用。) (还要注意then的上下文为x,需要用call来纠正)
  • 若不存在then,也直接resolve

catch的实现

  • 在then的基础上,只传第二个参数并返回

finally

  • 返回一个then执行,两个参数传入回调为返回promise.resolve(cb).then的Promise执行结果。

代码实现

const RESOLVED = 'RESOLVED' const REJECTED = 'REJECTED' const PENDING = 'PENDING' const resolvePromise = (promise2, x, resolve, reject) => { if (promise2 === x) { return reject(new TypeError('循环引用报错')) } if (x !== null && (typeof x === 'object' || typeof x === 'function')) { let called; try { let then = x.then if (typeof then === 'function') { then.call(x, y => { if (called) return called = true resolvePromise(promise2, y, resolve, reject) }, e => { if (called) return called = true reject(e) }) } else { resolve(x) } } catch (e) { if (called) return called = true reject(e) } } else { resolve(x) } } class Promise { constructor(executor) { this.status = PENDING this.value = undefined this.reason = undefined this.onfulfilledCallbacks = [] this.onrejectedCallbacks = [] let resolve = (value) => { if (value instanceof Promise) { return value.then(resolve, reject) } if (this.status === PENDING) { this.value = value this.status = RESOLVED this.onfulfilledCallbacks.forEach(fn => fn()) } } let reject = (reason) => { if (this.status === PENDING) { this.reason = reason this.status = REJECTED this.onrejectedCallbacks.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (e) { reject(e) } } then(onfulfilled, onrejected) { onfulfilled = typeof onfulfilled === 'function' ? onfulfilled : v => v; onrejected = typeof onrejected === 'function' ? onrejected : err => { throw err }; let promise2 = new Promise((resolve, reject) => { if (this.status === RESOLVED) { setTimeout(() => { try { let x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === REJECTED) { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) } if (this.status === PENDING) { this.onfulfilledCallbacks.push(() => { setTimeout(() => { try { let x = onfulfilled(this.value) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) this.onrejectedCallbacks.push(() => { setTimeout(() => { try { let x = onrejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (e) { reject(e) } }) }) } }) return promise2 } catch (onrejected) { return this.then(null, onrejected) } finally(cb) { return this.then( (data) => { return Promise.resolve(cb()).then(() => data) }, (err) => { return Promise.resolve(cb()).then(() => { throw err }) }) } static resolve(value) { return new Promise((resolve, reject) => { resolve(value) }) } static reject(reason) { return new Promise((resolve, reject) => { reject(reason) }) } static all(promises) { return new Promise((resolve, reject) => { let result = [] let times = 0 const processSuccess = (index, val) => { result[index] = val if (++times === promises.length) { resolve(result) } } for (let i = 0; i < promises.length; i++) { let p = promises[i]; if (p && typeof p.then === 'function') { p.then(data => { processSuccess(i, data) }, reject) } else { processSuccess(i, p) } } }) } static race(promises) { return new Promise((resolve, reject) => { for (let i = 0; i < promises.length; i++) { let p = promises[i]; if (p && typeof p.then === 'function') { p.then(data => { resolve(data) }, reject) } else { resolve(p) } } }) } } Promise.defer = Promise.deferred = function () { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve; dfd.reject = reject }) return dfd; } module.exports = Promise
标签:
评论(0)
暂无评论
暂无评论
留言板