手撕PromiseA+规范及其周边函数的源码实现

tech2022-07-13  171

‘回调地狱’是每个前端工程师的噩梦,promise/A+的出现让我们如梦初醒,原来异步编程还可以这样实现,promise让每一位前端工程师爱不释手。它规范化了前端异步编程,因此也成为了前端面试者躲不开的话题。今天我就把promise的源码实现分享给大家,供学习、参考。

Promise

console.log('-------------------promise源码解析----------------------') /** * 1. Promise 是一个类 exectuor 是一个立即执行函数 * 2. 有三个状态 默认是【PENDING】 FULFILED (成功态)、REJECTED(失败态),状态一经改变不能再修改 * 3. resolve和reject的结果传入到then中的回调函数中 * 4. 发布订阅模式实现异步执行 * 5. 如果promise返回一个普通值(不论是 resolve 还是reject中返回的)都传递到下一个then的成功中 * 6. 如果返回一个错误 一定走到下一次的失败 * 7. 如果返回的是一个promise 会采用promise的状态决定下一次的成功还是失败,如果离自己最近的then没有错误处理,会向下找。 * 8. 每次执行promise.then 都会返回一个'全新的promise' */ // 中间态 未决态 const PENDING = 'PENDING' // 成功态 const FULFILED = 'FULFILED' // 失败态 const REJECTED = 'REJECTED' const resolvePromise = (promise2, x, resolve, reject) => { // 循环引用 抛出异常 if (promise2 === x) { return reject(new TypeError('TypeError: Chaining cycle detected for promise #<Promise>')) } // 防止第三方库状态会来回改变,调用多次 let called; // 这里要进行严格的判断,因为这里还有兼容别人写的第三方的库实现的promise // 1. 先判断是否是一个promise if ((typeof x === 'object' && x !== null) || typeof x === 'function') { // 2.还要有then方法 /* Object.defineProperty(x,'then',{ get(){ throw new Error() } }) */ try { let then = x.then if (typeof then === 'function') { // 走到这里就认为是prommise // 不要写出x.then(),容易报错 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 (error) { if (called) return; called = true; reject(error) } } else { resolve(x) } } class MyPromise { constructor(executor) { this.status = PENDING; this.value = null; this.reason = null; // 发布订阅模式 this.onFulfiledcallback = []; this.onRejectedcallbalck = []; let resolve = (value) => { if (this.status === PENDING) { // 一旦成功,状态不能再改变 this.status = FULFILED this.value = value this.onFulfiledcallback.forEach(fn => fn()) } } let reject = (reason) => { if (this.status === PENDING) { // 一旦失败,状态不再改变 this.status = REJECTED; this.reason = reason; this.onRejectedcallbalck.forEach(fn => fn()) } } try { executor(resolve, reject) } catch (error) { // 如果异常,立即结束 console.log('error', 'inner') reject(error) } } then(onFulfailed, onRejected) { onFulfailed = typeof onFulfailed === 'function' ? onFulfailed : v => v; onRejected = typeof onRejected === 'function' ? onRejected : err => { throw err }; // then的链式调用的处理规范 const promise2 = new MyPromise((resolve, reject) => { if (this.status === FULFILED) { // 返回的x如果是一个普通值没有问题 // 1. 如果返回的是一个promise 怎么办??? // 2. 如果返回一个错误怎么办???/ ====> 会被executor的异常蒱货 // 3.此时的promise2还没有创建完毕,会报错 // 4.使用事件循环机制的宏任务来解决 // let x = onFulfailed(this.value) // console.log('x', x) // resolvePromise(promise2, x, resolve, reject) setTimeout(() => { // 5. 使用setTimeout之后,抛出的异常外面的executor的trycatch无法再蒱货到 // 6. 需要在这里再次trycatch try { let x = onFulfailed(this.value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }, 0) } if (this.status === REJECTED) { // let x = onRejected(this.reason) // console.log('x', x) // 返回的x如果是一个普通值没有问题 // 1. 如果返回的是一个promise 怎么办??? // 2. 如果返回一个错误怎么办???/ // resolvePromise(promise2, x, resolve, reject) setTimeout(() => { try { let x = onRejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }, 0); } if (this.status === PENDING) { // 已下方式是可以的,有可能我们还会处理其他逻辑, // 所以我们会使用AOP的思想来进行编程(面向切片编程) // this.onFulfiledcallback.push(onFulfailed) // this.onRejectedcallbalck.push(onRejected) this.onFulfiledcallback.push(() => { // todo other // let x = onFulfailed(this.value) // 返回的x如果是一个普通值没有问题 // 1. 如果返回的是一个promise 怎么办??? // 2. 如果返回一个错误怎么办???/ // resolvePromise(promise2, x, resolve, reject) setTimeout(() => { try { let x = onFulfailed(this.value) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }, 0) }) this.onRejectedcallbalck.push(() => { // todo other // let x = onRejected(this.reason) // 返回的x如果是一个普通值没有问题 // 1. 如果返回的是一个promise 怎么办??? // 2. 如果返回一个错误怎么办???/ // resolvePromise(promise2, x, resolve, reject) setTimeout(() => { try { let x = onRejected(this.reason) resolvePromise(promise2, x, resolve, reject) } catch (error) { reject(error) } }, 0); }) } }) return promise2 } catch(errCallback) { // 实质是没有成功参数的then方法 return this.then(null, errCallback) } } // Promise/A+ 规范 测试 MyPromise.deferred = function () { const dfd = {}; dfd.promise = new MyPromise((resolve, reject) => { dfd.resolve = resolve; dfd.reject = reject; }) return dfd; } // npm install promises-aplus-tests -g // promises-aplus-tests 16.手写promise.js module.exports = MyPromise

Promise.all(面试的机率 *****)

/* Promise.all 1.全部完成才叫完成 2.返回的还是一个promise */ /* Promise.all源码解析 */ Promise.all = function (promises) { return new Promise((resolve, reject) => { const arr = [] // 解决异步并发的问题 let i = 0; let processData = (index, data) => { arr[index] = data if (++i === promises.length) { resolve(arr) } } for (let i = 0; i < promises.length; i++) { let currentPromise = promises[i] if (isPromise(currentPromise)) { currentPromise.then(data => { processData(i, data) }, reject) } else { processData(i, currentPromise) } } }) } /** * 判断是否promise的方法 * @param {*} promise */ const isPromise = promise => { if ((typeof promise === 'object' && promise !== 'null') || typeof promise === 'function') { return typeof promise.then === 'function' } else { return false } }

Promise.race

/** Promise.race源码解析 * 1. 竞争机制 * 2.返回一个promise */ Promise.race = function (promises) { return new Promise((resolve, reject) => { for(let i = 0, len = promises.length; i < len; i++) { let currentPromise = promises[i]; if(isPromise(currentPromise)){ currentPromise.then(resolve,reject) }else{ resolve(currentPromise) } } }) } /* 1. 是对象或者函数 2. 具有then方法 */ const isPromise = (promise) =>{ if((typeof promise === 'object' && promise !== null) || typeof promise === 'function'){ return typeof promise.then === 'function' }else{ return false } }

Promise.resolve

/** * 静态方法Promise.resolve源码解析 * 1.返回一个Promise * 2.具有等待效果 */ Promise.resolve = function (data) { return new Promise((resolve, reject) => { resolve(data) }) }

Promise.reject

/** * 静态方法Promise.reject源码解析 * 1.返回一个Promise * 2.不具有等待效果 */ Promise.reject = function (reason) { return new Promise((resolve, reject) => { reject(reason) }) }

 

最新回复(0)