过程)"/>
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的基本特征:
- promise 有三个状态:
pending
,fulfilled,
rejected
new promise
时, 需要传递一个executor()
执行器,执行器立即执行executor
接受两个参数,分别是resolve
和reject
- promise 的默认状态是
pending
- promise 有一个
value
保存成功状态的值 - promise 有一个
reason
保存失败状态的值 - promise 只能从
pending
到rejected
, 或者从pending
到fulfilled
,状态一旦确认,就不会再改变 - promise 必须有一个
then
方法,then 接收两个参数,分别是 promise 成功的回调 onFulfilled, 和 promise 失败的回调 onRejected - 如果调用 then 时,promise 已经成功,则执行
onFulfilled
,参数是promise
的value
- 如果调用 then 时,promise 已经失败,那么执行
onRejected
, 参数是promise
的reason
- 如果 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(详细过程)
发布评论