关注 前端技术专栏 ,回复“ 资源 ”免费领取全套视频教程 前言 记得之前发过一篇关于Promise文章的讲解,不过都不是很深入,只是对使用上的理解,所以这次我将会带着各位通过JavaScript来实现一个Promise,并且是符合规范的,最后可以通过promises-aplus-tests来进行跑测。 整个实现主要通过Promise A+规范来做的,可以参考以下地址:
https://promisesaplus.com/
正文 接下来的内容我将直接贴出源码,因为我在写的时候都以逐行加了注释来说明代码理解,所以就不会再来逐行解读了,如各位从其中发现任何问题欢迎留言指正utils.js 文件
const { PENDING, FULFILLED, REJECTED, getType, isArray, isObject, isFunction} = { PENDING: 'pending', FULFILLED: 'fulfilled', REJECTED: 'rejected', getType: (t) => (v) => Object.prototype.toString.call(v) === `[object ${t}]`, isArray: (v) => getType('Array')(v), isObject: (v) => getType('Object')(v), isFunction: (v) => getType('Function')(v),}// 解析promise,这里将会处理返回的promise或者其它情况下promise的状态让其直接变为完成状态并将参数值传入到下一个thenconst resolvePromise = (promise2, x, resolve, reject) => { let caller = false // 定义一个开关,为了让promise的状态一旦确定则不能再做修改 // 如果promise是它自己,避免自己等待自己,直接抛错 if (promise2 === x) { return reject( new TypeError('Chaining cycle detected for promise #<Promise>') ) } // 如果x是对象或者是一个函数的时候 那么它可能是一个promise,接下来将进一步解析。 这里是为了兼容第三方promise库,例如:q es6-promise if ((x && isObject(x)) || isFunction(x)) { try { const then = x.then // 确定then是一个函数的时候,那么肯定是一个promise if (isFunction(then)) { // 执行then函数 then.call( x, y => { if (caller) return null caller = true // 递归解析,直到不是一个promise resolvePromise(promise2, y, resolve, reject) }, e => { if (caller) return null caller = true // 如果发生错误,将直接变为拒绝状态并返回错误信息 reject(e) } ) } else { // 如果不是一个promise,则直接将其状态变为完成并返回其值 resolve(x) } } catch (err) { if (caller) return null caller = true // 发生错误这里直接将状态变为拒绝并返回错误信息 reject(err) } } else { // 当x是一个普通值,那么将直接变为完成状态,并返回其值 resolve(x) }}// 专门用来处理then的onFulfilled Or onRejected 回调const onFulfilledOrOnRejectedHandler = ( promise2, onFulfilledOrOnRejectedCallBack, resolve, reject, value) => { // 此处的定时器为了等待Promise的实例完成 setTimeout(() => { try { // 执行then的resolve or reject函数并传入其值,通过一个变量x去拿到当前resolve执行后的返回值 const x = onFulfilledOrOnRejectedCallBack(value) // 解析then的resolve or reject执行,如果返回一个promise或者其它值情况的处理 resolvePromise(promise2, x, resolve, reject) } catch (err) { // 如果返回发生错误,则直接reject reject(err) } }, 0)}module.exports = { PENDING, FULFILLED, REJECTED, isArray, isObject, isFunction, onFulfilledOrOnRejectedHandler}
主文件 promise.js
const { PENDING, FULFILLED, REJECTED, isArray, isObject, isFunction, onFulfilledOrOnRejectedHandler} = require('./utils')class Promise { constructor(executor) { this.status = PENDING this.doneValue = undefined // 同步executor执行后,保存resolve函数参数值 this.resason = undefined // 同步executor执行后,保存reject函数的参数值 // 发布订阅模式。then方法执行时如发现状态未变,则订阅then方法执行的 完成 Or 拒绝 回调 this.doneCallbacks = [] this.failCallbacks = [] const resolve = (doneValue) => { // 如果值是一个promise if (doneValue instanceof Promise) { // 将递归解析resolve中的参数直到不是一个promise对象 return doneValue.then(resolve, reject) } // 判断只有是等待状态的时候才进行成功处理,为了一旦状态发生改变将不会再改变状态 if (this.status === PENDING) { this.status = FULFILLED this.doneValue = doneValue // 执行then方法的resolve订阅回调 this.doneCallbacks.forEach((fn) => fn()) } } const reject = (resason) => { // 判断只有是等待状态的时候才进行拒绝处理,为了一旦状态发生改变将不会再改变状态 if (this.status === PENDING) { this.status = REJECTED this.resason = resason // 执行then方法的reject订阅回调 this.failCallbacks.forEach((fn) => fn()) } } // 异常处理,一旦发生错误直接将状态变为拒绝并返回错误信息 try { // 同步执行 executor promise的回调 executor(resolve, reject) } catch (e) { reject(e) } } // 内部定时器的作用是为了等待Promise的实例完成再执行 then(onFulfilled, onRejected) { // 如果 onFulfilled Or onRejected 不是函数,则将其忽略,默认赋值一个函数返回其值,为了让值往下穿透 onFulfilled = isFunction(onFulfilled) ? onFulfilled : v => v onRejected = isFunction(onRejected) ? onRejected : (err) => { throw err } // then的执行必须返回一个新的promise,形成无限链式调用(也就是形成递归) const promise2 = new Promise((resolve, reject) => { let value = '' let onFulfilledOrOnRejectedCallBack = '' // 如果状态已变成完成状态 则保存onFulfilled回调 并保存完成的donevalue if (this.status === FULFILLED) { onFulfilledOrOnRejectedCallBack = onFulfilled value = this.doneValue } // 如果状态已变成完成状态 则保存onRejected回调 并保存拒绝的resason if (this.status === REJECTED) { onFulfilledOrOnRejectedCallBack = onRejected value = this.resason } // 执行对应状态的 onFulfilled Or onRejected 并传入对应的value if (isFunction(onFulfilledOrOnRejectedCallBack)) { setTimeout(() => { onFulfilledOrOnRejectedHandler( promise2, onFulfilledOrOnRejectedCallBack, resolve, reject, value ) }, 0) } // 如果状态不变 if (this.status === PENDING) { // 订阅then的完成回调 this.doneCallbacks.push(() => { setTimeout(() => { onFulfilledOrOnRejectedHandler( promise2, onFulfilled, resolve, reject, this.doneValue ) }, 0) }) // 订阅then的拒绝回调 this.failCallbacks.push(() => { setTimeout(() => { onFulfilledOrOnRejectedHandler( promise2, onRejected, resolve, reject, this.resason ) }, 0) }) } }) return promise2 } // catch的回调利用then方法的实现 catch(failCallback) { return this.then(null, failCallback) } // finally 是无论如何都会执行的 // 如果返回一个promise,那么将会等待这个promise执行完毕 finally(callback) { return this.then( x => Promise.resolve(callback()).then(() => x), e => Promise.reject(callback()).then(() => { throw e }) ) } // resolve 的静态方法 static resolve(v) { return new Promise((resolve) => { resolve(v) }) } // reject 的静态方法 static reject(err) { return new Promise((resolve, reject) => { reject(err) }) } static all(promises) { // 看一下进来的参数是不是一个数组 promises = isArray(promises) ? promises : [] let fulfilledCount = 0 // 状态变完成的个数 let promisesLength = promises.length // 需要完成的个数 let results = new Array(promisesLength) // 设置结果数组长度 return new Promise((resolve, reject) => { // 如果是个空数组,那么将直接变为完成状态,并传入空数组参数值 if (promisesLength === 0) return resolve([]) // 遍历数组中的promise promises.forEach((promise, index) => { // 判断是不是一个promise if (isObject(promise) && isFunction(promise.then)) { promise.then( (value) => { // 向结果数组中存入 对应返回数据值 results[index] = value // 当等于了需完成的个数,说明已全部都处理完了,那么就直接将状态变为完成,返回最终数据 if (++fulfilledCount === promisesLength) resolve(results) }, (err) => reject(err) // 只要一个发生错误,那么直接变为失败,并返回失败原因 ) } else { // 如果不是一个promise,将直接存值 results[index] = promise if (++fulfilledCount === promisesLength) resolve(results) } }) }) } // 看谁快 static race(promises) { promises = isArray(promises) ? promises.filter(item => isObject(item) && isFunction(item.then)) : [] return new Promise((resolve, reject) => { promises.forEach((promise) => { promise.then( (value) => resolve(value), (err) => reject(err) ) }) }) }}// 延迟执行,这个主要用于promise A+规范跑测使用Promise.defer = Promise.deferred = () => { let dfd = {} dfd.promise = new Promise((resolve, reject) => { dfd.resolve = resolve dfd.reject = reject }) return dfd}module.exports = Promise
结语
以上就是全部的代码了,代码不是很多,Promise A+规范主要在于then方法,其它辅助方法都比较容易实现。
下面是这个源码的仓库地址,如果想直接测试一下可以拉下来跑一跑
https://github.com/wujiabk/promise
猜你爱看 一文搞懂Linux CentOS7中关于MongoDB的认证和授权设置 只需5分钟,让你了解未来可能推翻Node的新轮子 Deno 1.0 Vue 3.0 初体验《从构建项目到实现一个todoList》微 博:前端吴佳
QQ群:856363266
长按识别二维码
关注「前端技术专栏」 加星标
每天给您推送最新原创技术文章
好看,帮点击在看 ❤️