JS手写Promise(详细过程)

编程入门 行业动态 更新时间:2024-10-26 08:30:42

JS手写Promise(详细<a href=https://www.elefans.com/category/jswz/34/1769466.html style=过程)"/>

JS手写Promise(详细过程)

PS:JS手写Promise方法的整理在下一篇文章

手写Promise的API(resolve,reject,then,catch,finally,all)_Eric加油学!的博客-CSDN博客

1、基础版Promise

首先,通过一个简单的Promise例子回顾其使用

const promise = new Promise((resolve, reject) => {resolve('ok')
});
promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})

控制台输出 promise success: ok

  • 首先我们在调用 Promise 时,会返回一个 Promise 对象  
  • 构建 Promise 对象时,需要传入一个 executor 函数,Promise 的主要业务流程都在 executor 函数中执行  
  • 如果运行在 excutor 函数中的业务执行成功了,会调用 resolve 函数;如果执行失败了,则调用 reject 函数  
  • Promise 的状态不可逆,同时调用 resolve 函数和 reject 函数,默认会采取第一次调用的结果

所以,我们可以得出一些Promise的基本特征:

  1. promise 有三个状态:pendingfulfilled,rejected 
  2. new promise时, 需要传递一个executor()执行器,执行器立即执行
  3. executor接受两个参数,分别是resolvereject
  4. promise 的默认状态是 pending
  5. promise 有一个value保存成功状态的值
  6. promise 有一个reason保存失败状态的值
  7. promise 只能从pendingrejected, 或者从pendingfulfilled,状态一旦确认,就不会再改变
  8. promise 必须有一个then方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected
  9. 如果调用 then 时,promise 已经成功,则执行onFulfilled,参数是promisevalue
  10. 如果调用 then 时,promise 已经失败,那么执行onRejected, 参数是promisereason
  11. 如果 then 中抛出了异常,那么就会把这个异常作为参数,传递给下一个 then 的失败的回调onRejected

根据以上特征,就可以写一些基础版的Promise了

class Promise {// Promise 等待态(初始状态)static PENDING = 'pending';// Promise 失败态static REJECTED = 'rejected';// Promise 成功态static FULFILLED = 'fulfilled';constructor(executor){// 初始化 Promise 初始状态this.status = Promise.PENDING;// 定义 Promise 成功的值this.value = undefined// 定义 Promise 失败的原因this.reason = undefined;// 定义 resolve 函数const resolve = (value) => {if(this.status === Promise.PENDING){this.status = Promise.FULFILLED;this.value = value}}// 定义 reject 函数const reject = (reason) => {if(this.status === Promise.PENDING){this.status = Promise.REJECTED;this.reason = reason}};try {executor(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled,onRejected){if(this.status === Promise.FULFILLED){onFulfilled(this.value)}if(this.status === Promise.REJECTED){onRejected(this.reason)}}
}module.exports = Promise;

对其进行测试:

const myPromise = require('./promise')const promise = new myPromise((resolve, reject) => {resolve('ok')
});
promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})

输出: promise success: ok

 至此,一个简单的Promise就手写完毕了。不过目前只是实现了同步操作。如果在executor中有一个异步任务呢?

const promise = new Promise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})

对于原生Promise,它的输出肯定是 在2秒后打印  promise success:ok

const myPromise = require('./promise')const promise = new myPromise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})

但对于我们刚才手写的基础版Promise而言,它是没有任何输出的

因为setTimeout是一个异步任务,executor执行到这发现是异步任务,暂时不去处理放入微队列,然后执行then时,promise实例的状态其实还是pending,所以不会执行任何操作。但确实2s后,它们的状态变为了fulfilled,我们可以稍微测试一下

const myPromise = require('./promise')const promise = new myPromise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})
setTimeout(()=>{console.log(promise);
},2000)

2s后输出  Promise { status: 'fulfilled', value: 'ok', reason: undefined }

所以,在这个逻辑上,我们能否把成功和失败的回调先存储起来,当executor中的异步任务被执行时,触发resolve或reject再依次调用其回调呢?

class Promise {// Promise 等待态(初始状态)static PENDING = 'pending';// Promise 失败态static REJECTED = 'rejected';// Promise 成功态static FULFILLED = 'fulfilled';constructor(executor){// 初始化 Promise 初始状态this.status = Promise.PENDING;// 定义 Promise 成功的值this.value = undefined// 定义 Promise 失败的原因this.reason = undefined;// 定义存储 then 方法中成功的回调this.onFulfilledCallbacks = [];// 定义存储 then 方法中失败的回调this.onRejectedCallbacks = [];// 定义 resolve 函数const resolve = (value) => {if(this.status === Promise.PENDING){this.status = Promise.FULFILLED;this.value = valuethis.onFulfilledCallbacks.forEach(fn => fn())}}// 定义 reject 函数const reject = (reason) => {if(this.status === Promise.PENDING){this.status = Promise.REJECTED;this.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())}};try {executor(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled,onRejected){if(this.status === Promise.FULFILLED){onFulfilled(this.value)}if(this.status === Promise.REJECTED){onRejected(this.reason)}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {onFulfilled(this.value)})this.onRejectedCallbacks.push(() => {onRejected(this.reason)})}}
}module.exports = Promise;

我们的思路是:

1、既然执行到then时,由于有异步任务,所以状态仍是 pending,那我们先对其状态进行判断 if(this.status === Promise.PENDING) ,对resolve和reject的回调进行存储

2、定义存储then中resolve和reject的回调,考虑到可能不只会有一个then方法,所以我们应该定义为 数组

3、当 执行到异步任务 时,他们的状态进行变化,我们在相应的resolve和reject函数中对数组里存储的各个回调依次调用

进行测试:

const myPromise = require('./promise')const promise = new myPromise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})

 2s后输出 promise success: ok 


此外,Promise还有一个优势在于其链式调用,它可以让我们使用Promise时,当then函数中,return了一个值,我们可以在下一个then中获取到。例如: promise.then().then()

其实这种写法也等同于

const promise2 = promise.then((value) => {},(reason) => {})promise2.then(......)

所以先对原生的Promise进行试验:

const promise = new Promise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
const promise2 = promise.then((value) => {console.log("promise success:", value);
}, (reason) => {console.log("promise fail:", reason);
})promise2.then((value)=>{console.log("promise2 success:", value);
},(reason)=>{console.log("promise2 fail:", reason);
})

2s后输出:

promise success: ok
promise2 success: undefined

因为我们没有写promise中then方法的返回值,而没有写的话,函数的返回值默认是undefined 

const promise = new Promise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
const promise2 = promise.then((value) => {console.log("promise success:", value);return 123
}, (reason) => {console.log("promise fail:", reason);
})promise2.then((value)=>{console.log("promise2 success:", value);
},(reason)=>{console.log("promise2 fail:", reason);
})

 如果promise的then有返回值,则输出为

promise success: ok
promise2 success: 123

class Promise {// Promise 等待态(初始状态)static PENDING = 'pending';// Promise 失败态static REJECTED = 'rejected';// Promise 成功态static FULFILLED = 'fulfilled';constructor(executor){// 初始化 Promise 初始状态this.status = Promise.PENDING;// 定义 Promise 成功的值this.value = undefined// 定义 Promise 失败的原因this.reason = undefined;// 定义存储 then 方法中成功的回调this.onFulfilledCallbacks = [];// 定义存储 then 方法中失败的回调this.onRejectedCallbacks = [];// 定义 resolve 函数const resolve = (value) => {if(this.status === Promise.PENDING){this.status = Promise.FULFILLED;this.value = valuethis.onFulfilledCallbacks.forEach(fn => fn())}}// 定义 reject 函数const reject = (reason) => {if(this.status === Promise.PENDING){this.status = Promise.REJECTED;this.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())}};try {executor(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled,onRejected){return new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){const x = onFulfilled(this.value)resolve(x)}if(this.status === Promise.REJECTED){onRejected(this.reason)}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {const x = onFulfilled(this.value)resolve(x);})this.onRejectedCallbacks.push(() => {onRejected(this.reason)})}})}
}module.exports = Promise;

 所以,只需要在then函数里面,返回一个新的Promise即可,并且获取成功回调函数的返回值,暴露给resolve

测试后:

promise success: ok
promise2 success: 123 

再看原生Promise对于失败的处理,promise状态变为rejected,promise2走的是 成功的回调。

只有promise中抛错或者是返回一个rejected状态的Promise,promise2才会走失败的回调

const promise = new Promise((resolve, reject) => {setTimeout(()=>{reject('ok')},2000)
});
const promise2 = promise.then((value) => {console.log("promise success:", value);return 123
}, (reason) => {console.log("promise fail:", reason);
})promise2.then((value)=>{console.log("promise2 success:", value);
},(reason)=>{console.log("promise2 fail:", reason);
})

promise fail: ok
promise2 success: undefined 

如果我们暂时先不管promise里面抛错或者返回rejected的Promise,那其实和成功一样,我们获取回调返回值并暴露给resolve即可。

then(onFulfilled,onRejected){return new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){const x = onFulfilled(this.value)resolve(x)}if(this.status === Promise.REJECTED){const x = onRejected(this.reason)resolve(x)}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {const x = onFulfilled(this.value)resolve(x);})this.onRejectedCallbacks.push(() => {const x = onRejected(this.reason)resolve(x);})}})}

 再考虑一步,如果promise里面抛错了,要如何处理,其实就是可以用try catch捕获一下,一旦抛错,直接reject即可

then(onFulfilled,onRejected){return new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){try {const x = onFulfilled(this.value)resolve(x)} catch (e) {reject(e)}}if(this.status === Promise.REJECTED){try {const x = onRejected(this.reason)resolve(x)} catch (e) {reject(e)}}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {try {const x = onFulfilled(this.value)resolve(x);} catch (e) {reject(e)}})this.onRejectedCallbacks.push(() => {try {const x = onRejected(this.reason)resolve(x);} catch (e) {reject(e)}})}})
}

至此,promise里面抛错和返回普通值 已经处理好了。 那如果promise里面返回new Promise呢


原生Promise的执行效果如下

const promise = new Promise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
const promise2 = promise.then((value) => {console.log("promise success:", value);return new Promise((resolve,reject) => {resolve('ok2')})
}, (reason) => {console.log("promise fail:", reason);
})promise2.then((value)=>{console.log("promise2 success:", value);
},(reason)=>{console.log("promise2 fail:", reason);
})

promise success: ok
promise2 success: ok2

而目前我们的myPromise的输出是如下的:

promise success: ok
promise2 success: Promise {
  status: 'fulfilled',
  value: 'ok2',
  reason: undefined,
  onFulfilledCallbacks: [],
  onRejectedCallbacks: []
}

因为我们直接获取了它的返回值记为x,并resolve(x)。所以可以进行一些处理逻辑 


由于这些处理逻辑基本都一样,所以可以提出去,单独写一个函数

const resolvePromise = (promise2, x, resolve, reject) => {}

 这里接收4个参数,分别是 我们要返回的new Promise2,promise返回的promise,要返回的resolve和reject回调

所以可以这么写(其余的几个if判断里的处理也一样)

    then(onFulfilled,onRejected){return new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}

这里的promise2是哪里来的呢?其实就是外层要return的这个new Promise,所以我们可以先定义,再最后return

then(onFulfilled,onRejected){const promise2 = new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}}......}return promise2

但使用这个promise2,是在promise2的定义体内部的,咋获取?

可以使用setTimeout,把它变成异步就可以获取到promise2了

    then(onFulfilled,onRejected){const promise2 = new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)

    then(onFulfilled,onRejected){const promise2 = new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)}if(this.status === Promise.REJECTED){setTimeout(()=>{try {const x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)})this.onRejectedCallbacks.push(() => {setTimeout(()=>{try {const x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject);    } catch (e) {reject(e)}},0)})}})return promise2}

所以,接下来就只要完成resolvePromise方法即可

const resolvePromise = (promise2, x, resolve, reject) => {// 自己等待自己完成的情况, 直接抛错if(x === promise2){return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if((typeof x === 'object' && x !== null) || typeof x === 'function'){try { // 这里防止返回的对象里面,调用then会报错的情况const then = x.then;if(typeof then === 'function'){ // 如果then是一个函数,那x就是Promise对象then.call(x, (y) => {resolve(y)},(r) => {reject(r)})} else { // 普通对象,上面有then属性而已resolve(x)}} catch (e) {reject(e)}}else{// 不是对象也不是函数,那就是普通值,直接resolveresolve(x)}
}class Promise {// Promise 等待态(初始状态)static PENDING = 'pending';// Promise 失败态static REJECTED = 'rejected';// Promise 成功态static FULFILLED = 'fulfilled';constructor(executor){// 初始化 Promise 初始状态this.status = Promise.PENDING;// 定义 Promise 成功的值this.value = undefined// 定义 Promise 失败的原因this.reason = undefined;// 定义存储 then 方法中成功的回调this.onFulfilledCallbacks = [];// 定义存储 then 方法中失败的回调this.onRejectedCallbacks = [];// 定义 resolve 函数const resolve = (value) => {if(this.status === Promise.PENDING){this.status = Promise.FULFILLED;this.value = valuethis.onFulfilledCallbacks.forEach(fn => fn())}}// 定义 reject 函数const reject = (reason) => {if(this.status === Promise.PENDING){this.status = Promise.REJECTED;this.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())}};try {executor(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled,onRejected){const promise2 = new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)}if(this.status === Promise.REJECTED){setTimeout(()=>{try {const x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)})this.onRejectedCallbacks.push(() => {setTimeout(()=>{try {const x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject);    } catch (e) {reject(e)}},0)})}})return promise2}
}module.exports = Promise;

这时,进行测试,就正常了

const myPromise = require('./promise')const promise = new myPromise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
const promise2 = promise.then((value) => {console.log("promise success:", value);return new Promise((resolve,reject) => {resolve('ok2')})
}, (reason) => {console.log("promise fail:", reason);
})promise2.then((value)=>{console.log("promise2 success:", value);
},(reason)=>{console.log("promise2 fail:", reason);
})

promise success: ok
promise2 success: ok2

但如果resolve里面继续new Promise呢,目前只做了一层的处理,所以我们还要递归解析

const promise2 = promise.then((value) => {console.log("promise success:", value);return new Promise((resolve,reject) => {resolve(new Promise((resolve,reject)=>{resolve('ok2')}))})
}, (reason) => {console.log("promise fail:", reason);
})

 这样就可以处理嵌套的new Promise情况了


还没结束,如果在promise的return中,连续执行回调,它也会连续执行

const Promise = require('./promise')const promise = new Promise((resolve, reject) => {setTimeout(()=>{resolve('ok')},2000)
});
const promise2 = promise.then((value) => {console.log("promise success:", value);return {then(onFulfilled,onRejected){throw new Error(onFulfilled('ok'))}}
}, (reason) => {console.log("promise fail:", reason);
})promise2.then((value)=>{console.log("promise2 success:", value);
},(reason)=>{console.log("promise2 fail:", reason);
})

 

这样肯定是不对的,不可能既成功又失败。 所以应该只让它执行一次 

所以可以设置一个变量called,分别在成功和失败的执行中进行控制

const resolvePromise = (promise2, x, resolve, reject) => {// 自己等待自己完成的情况, 直接抛错if(x === promise2){return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if((typeof x === 'object' && x !== null) || typeof x === 'function'){let called = false;try { // 这里防止返回的对象里面,调用then会报错的情况const then = x.then;if(typeof then === 'function'){ // 如果then是一个函数,那x就是Promise对象then.call(x, (y) => {if(called) return;called = true;resolvePromise(promise2, y, resolve, reject)},(r) => {reject(r)})} else { // 普通对象,上面有then属性而已resolve(x)}} catch (e) {if(called) return;called = true;reject(e)}}else{// 不是对象也不是函数,那就是普通值,直接resolveresolve(x)}
}

至此,就实现了Promise最为关键的部分: then的链式调用

完整代码如下:

const resolvePromise = (promise2, x, resolve, reject) => {// 自己等待自己完成的情况, 直接抛错if(x === promise2){return reject(new TypeError('Chaining cycle detected for promise #<Promise>'))}if((typeof x === 'object' && x !== null) || typeof x === 'function'){let called = false;try { // 这里防止返回的对象里面,调用then会报错的情况const then = x.then;if(typeof then === 'function'){ // 如果then是一个函数,那x就是Promise对象then.call(x, (y) => {if(called) return;called = true;console.log('test');resolvePromise(promise2, y, resolve, reject)},(r) => {reject(r)})} else { // 普通对象,上面有then属性而已resolve(x)}} catch (e) {if(called) return;called = true;console.log('test');reject(e)}}else{// 不是对象也不是函数,那就是普通值,直接resolveresolve(x)}
}class Promise {// Promise 等待态(初始状态)static PENDING = 'pending';// Promise 失败态static REJECTED = 'rejected';// Promise 成功态static FULFILLED = 'fulfilled';constructor(executor){// 初始化 Promise 初始状态this.status = Promise.PENDING;// 定义 Promise 成功的值this.value = undefined// 定义 Promise 失败的原因this.reason = undefined;// 定义存储 then 方法中成功的回调this.onFulfilledCallbacks = [];// 定义存储 then 方法中失败的回调this.onRejectedCallbacks = [];// 定义 resolve 函数const resolve = (value) => {if(this.status === Promise.PENDING){this.status = Promise.FULFILLED;this.value = valuethis.onFulfilledCallbacks.forEach(fn => fn())}}// 定义 reject 函数const reject = (reason) => {if(this.status === Promise.PENDING){this.status = Promise.REJECTED;this.reason = reasonthis.onRejectedCallbacks.forEach(fn => fn())}};try {executor(resolve, reject);} catch (e) {reject(e);}}then(onFulfilled,onRejected){const promise2 = new Promise((resolve, reject)=>{if(this.status === Promise.FULFILLED){setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)}if(this.status === Promise.REJECTED){setTimeout(()=>{try {const x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)}if(this.status === Promise.PENDING){this.onFulfilledCallbacks.push(() => {setTimeout(()=>{try {const x = onFulfilled(this.value)resolvePromise(promise2, x, resolve, reject);} catch (e) {reject(e)}},0)})this.onRejectedCallbacks.push(() => {setTimeout(()=>{try {const x = onRejected(this.reason)resolvePromise(promise2, x, resolve, reject);    } catch (e) {reject(e)}},0)})}})return promise2}
}module.exports = Promise;

剩下的就是Promise的一些其他方法:resolve、reject、catch、finally、all等

手写Promise的API(resolve,reject,then,catch,finally,all)_Eric加油学!的博客-CSDN博客

 如有帮助,三连一下呀

更多推荐

JS手写Promise(详细过程)

本文发布于:2024-03-09 08:50:38,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1724521.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:过程   详细   JS   Promise

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!