Promise核心实现
核心
构造函数核心
- 维护状态变量,只能由pending变为resolve或者reject
- 维护一个存储结果的变量
- 维护一个回调数组,执行到then,如果我们传入的立即执行函数没有立即执行resolve或者reject,所以promise的状态还是pending,这时要把then里面的回调函数保存起来。待到resolve或者reject执行后则执行回调数组里存到方法。若传入的立即执行函数直接执行了resolve或者reject此时就不用把回调保存起来,直接执行onResolved或onRejected方法。注意是异步执行。而且是做为微任务的。(下面我们用setTimeout模拟)
then核心
- 执行时,若当前状态为pending,则把回调保存到回调数组,若为resolve或者reject则直接异步执行(微任务)。如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。即resolve(result)或者reject(result)
- 每次then都返回一个新的Promise。
- promise会发生值传透,当then中传入的不算函数,则这个then返回的promise的data,将会保存上一个的promise.data。这就是发生值穿透的原因。而且每一个无效的then所返回的promise的状态都为resolved。
核心实现
将Promise向外暴露
(function (window) { /* Promise构造函数 executor:执行器函数 */ function Promise(executor) { } // 向外暴露Promise window.Promise = Promise })()
构造函数实现
function MyPromise(exector) { var self = this; self.status = 'pending'; // 给promise对象指定status属性,初始值为pending self.data = undefined; // 给promise对象指定一个存储结果的data self.callbacks = []; // 每个元素的结构 {onResolved(){},onRejected(){}} function resolve(value) { if(self.status !== 'pending') { return } self.status = 'resolved'; // 将状态更改为resolved self.data = value; // 保存value的值 // 异步调用resolve才会在这里执行 // 如果有待执行的callback函数,立即异步执行回调函数onResolved(); if(self.callbacks.length > 0) { self.callbacks.forEach(callbacksObj => { callbacksObj.onResolved(value); }); } } function reject() { // 如果当前状态不是pending,则不执行 if(self.status !== 'pending'){ return } // 将状态改为rejected self.status = 'rejected'; // 保存value的值 self.data = value; // 如果有待执行的callback函数,立即异步执行回调函数onResolved if (self.callbacks.length>0){ self.callbacks.forEach(callbackObj=>{ callbackObj.onRejected(value) }) } } // 立即同步执行exector // 注意⚠️:当在执行executor的时候,如果执行异常的话,这个promise的状态会直接执行reject方法 try{ // 立即同步执行executor executor(resolve,reject); } catch (e) { // 如果执行器抛出异常,promise对象变为rejected状态 reject(e); } }
then实现
MyPromise.prototype.then = function(onResolved, onReject) { var self = this; // 处理值穿透 onResolved = typeof onResolved === 'function'? onResolved: value => value onRejected = typeof onRejected === 'function'? onRejected: reason => {throw reason} return new myPromise((resolve,reject) => { if(self.status === 'pending') { // promise当前状态还是pending状态,将回调函数保存起来 self.callbacks.push({ onResolved() { handle(onResolved) }, onRejected() { handle(onRejected) } }) } else if (self.status === 'resolved') { setTimeout(()=>{ handle(onResolved) }) } else { // 当status === 'rejected' setTimeout(()=>{ handle(onRejected) }) } // 处理函数 function handle(callback) { try { const result = callback(self.data) if (result instanceof MyPromise){ // 如果回调函数返回的是promise,return的promise的结果就是这个promise的结果 result.then( value => {resolve(value)}, reason => {reject(reason)} ) } else { // 如果回调函数返回的不是promise,return的promise的状态是resolved,value就是返回的值。 resolve(result) } } catch (e) { // 如果执行onResolved的时候抛出错误,则返回的promise的状态为rejected reject(e) } } }); }
其他方法实现
catch
借用then方法
MyPromise.prototype.catch = function(onRejected){ return this.then(undefined,onRejected) }
finally
借用then方法
MyPromise.prototype.finally = (onFinally) => { return this.then((res)=>{ MyPromise.resolve(onFinally()).then(()=> res) },(reson)=>{ MyPromise.resolve(onFinally()).then(()=> reson) }) }
resolve
Promise参数可以为如下三种
- 不是promise
- 成功状态的promise
- 失败状态的promise
MyPromise.resolve = function(value){ return new MyPromise((resolve,reject)=>{ if (value instanceof Promise){ // 如果value 是promise value.then( value => {resolve(value)}, reason => {reject(reason)} ) } else{ // 如果value不是promise resolve(value) } } }
reject
MyPromise.reject = function(reason) { return new MyPromise((resolve,reject)=>{ reject(reason) }) }
all
- 入参一般是个由Promise实例组成的数组,但是也可以不是数组,但必须具有 Iterator 接口,且返回的每个成员都是 Promise 实例。若参数如果不是 Promise 实例,就会先调用Promise.resolve()方法,将参数转为 Promise 实例,再进一步处理。
- 返回值是个promise,因为可以使用.then
- 如果全部成功,状态变为resolved, 并且返回值组成一个数组传给回调
- 但凡有一个失败,状态变为rejected, 并将error返回给回调
MyPromise.all = (promisesArr) => { // 返回Promise return new MyPromise((resolve, reject) => { let dataArr = new Array(promisesArr.length); let count = 0; for (let i = 0; i < promisesArr.length; i++) { // 在 .then 中收集数据,并添加 .catch,在某一个 Promise 遇到错误随时 reject。 // 这样,在最外面调用 Promise.all().catch() 时也可以 catch 错误信息 // 判断当前这个元素是否为Promise对象,不是则转为Promise对象 let currentPromise = (promisesArr[i] instanceof Promise) ? promisesArr[i] : Promise.resolve(promisesArr[i]); currentPromise.then(res => { dataArr[index] = data; count++; // 如果数据收集完了,就把收集的数据 resolve 出去 if (count === promisesArr.length) resolve(dataArr); }).catch(err => { //如果某一个失败,promise.all()立即执行reject回调。 //但剩余的promise依旧继续执行,只不过对promise.all的结果不会产生影响了 reject(err) }); } })
注意⚠️:dataArr添加时用下标而不用数组时为了防止顺序错乱
race
返回一个promise对象,状态由第一个完成的promise决定
MyPromise.race = function(promisesArr){ return new Promise((resolve,reject)=>{ // 遍历promises,获取每个promise的结果 for (let i = 0; i < promisesArr.length; i++) { // 判断当前这个元素是否为Promise对象,不是则转为Promise对象 let currentPromise = (promisesArr[i] instanceof Promise) ? promisesArr[i] : Promise.resolve(promisesArr[i]); currentPromise.then( value => { // 只要有一个成功,返回的promise的状态九尾resolved resolve(value) }, reason => { //只要有一个失败,return的promise状态就为reject reject(reason) } ) }) }) }
allSettled
Promise.allSettled() 方法返回一个在所有给定的 promise 已被决议或被拒绝后决议的 promise,并带有一个对象数组,每个对象表示对应的promise 结果。
Promise.newAllSettled = function (promisesArr) { return new Promise((resolve, reject) => { let results = []; let count = 0; let promisesArrLength = promisesArr.length; // 运行所有的 Promise for (let i = 0; i < promisesArr.length; i++) { // 判断当前这个元素是否为Promise对象,不是则转为Promise对象 let currentPromise = (promisesArr[i] instanceof Promise) ? promisesArr[i] : Promise.resolve(promisesArr[i]); currentPromise.then(res => { // 当有 Promise 被 resolve 之后,记录 resolve 值和状态,已决 Promise 计数加一 results.push({value: res, status: 'fulfilled'}); count++; // 全部 Promise 已决,resolve if (count === promisesArrLength) { resolve(results); } }).catch(err => { // 当有 Promise 被 reject 后,记录 reject 值和状态,并且已决的 Promise 计数加一 results.push({value: err, status: 'rejected'}); count++; if (count === promisesArrLength) { resolve(results); } }); } }) };
参考
https://juejin.im/post/6844904088963022856
https://juejin.im/post/6850037281206566919
https://blog.csdn.net/MichelleZhai/article/details/104475521
https://zhuanlan.zhihu.com/p/60287801
https://zhuanlan.zhihu.com/p/41502945
https://zhuanlan.zhihu.com/p/61681036
语雀链接🔗 https://www.yuque.com/suihangadam
归来卧占楼千尺,梦落沧波明月舟。