手把手带你实现promise源码:培训班小张看后工资暴涨5k
Posted 前端呆头鹅
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了手把手带你实现promise源码:培训班小张看后工资暴涨5k相关的知识,希望对你有一定的参考价值。
文章目录
本文较长,看后工资暴涨,建议抢先收藏。
一 主干部分
我们首先实现promise主干部分。
1.1 回调函数和状态管理
1 实现promise,就是实现一个类,接收一个立即执行的执行器(回调函数);
2 内含有三种状态,pending fulfilled rejected。状态确定不可更改;
3 含有resolve和reject函数用来更改状态。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class promiseDemo{
constructor(fn){
console.log(this.status)
fn(this.resolve, this.reject)
console.log(this.status)
}
status = PENDING
resolve = () => {
if(this.status !== PENDING) return
this.status = FULFILLED
}
reject = () => {
if(this.status !== PENDING) return
this.status = REJECTED
}
}
我们可以使用这个模拟类。
new promiseDemo((res, rej) => {
console.log(1)
res()
})
打印结果:
目前我们实现了回调函数执行和状态管理部分,接下来实现then的链式调用。
1.2 实现then函数
1 then定义在原型对象中,接受两个回调函数,根据状态的不同调用不同回调函数。
2 回调函数中接受参数,来自于调用resolve和reject时给出的参数。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class promiseDemo{
constructor(fn){
console.log(this.status)
fn(this.resolve, this.reject)
console.log(this.status)
}
status = PENDING
value = undefined // 保存resolve调用时的参数
reason = undefined // 保存reject调用时的参数
resolve = value => {
if(this.status !== PENDING) return
this.status = FULFILLED
this.value = value // 保存参数等待then调用
}
reject = reason => {
if(this.status !== PENDING) return
this.status = REJECTED
this.reason = reason // 保存参数等待then调用
}
then (successCallback, failCallback) { // 根据状态调用不同回调函数 为回调函数传入对应参数
if(this.status === FULFILLED) {
successCallback(this.value)
}else if(this.status === REJECTED) {
failCallback(this.reason)
}
}
}
现在我们可以在实例后添加then,根据状态执行对应回调,并在回调函数中使用resolve/reject中传递的参数。
new promiseDemo((res, rej) => {
res(666)
}).then(res=>{
console.log('res', res)
}, rej=>{
console.log('rej', rej)
})
打印结果:
二 异步逻辑添加
当加入异步逻辑(如定时器),进入then时状态为pending,这时先将回调函数存储起来,当对应状态改变时调用。
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class promiseDemo{
constructor(fn){
console.log(this.status)
fn(this.resolve, this.reject)
console.log(this.status)
}
...
failCailback = undefined
successCallback = undefined
resolve = value => {
...
this.successCallback && this.successCallback(this.value) // 执行存储的回调
}
reject = reason => {
...
this.failCallback && this.failCallback(this.reason) // 执行存储的回调
}
then (successCallback, failCallback) {
if(this.status === FULFILLED) {
successCallback(this.value)
}else if(this.status === REJECTED) {
failCallback(this.reason)
}else { // 如果状态为pending 则将回调函数存储
this.failCailback = failCallback
this.successCallback = successCallback
}
}
}
调用如下:
new promiseDemo((res, rej) => {
setTimeout(() => {
console.log('2秒后')
res(666)
}, 2000)
}).then(res => {
console.log('res', res)
}, rej=>{
console.log('rej', rej)
})
打印结果:
三 then的链式调用
使then方法返回promise对象,就可以链式调用。
在then方法中创建promise对象实例并返回。
3.1 返回简单值
下面做一个链式调用的简单实现:
const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'
class promiseDemo{
...
then (successCallback, failCallback) {
// 创建promise对象实例并返回
let proRes = new promiseDemo((res, rej) => {
// 逻辑放到这个位置是为了使用res/rej抛出结果 使后续then可以捕捉状态和参数
if(this.status === FULFILLED) {
// 捕捉返回值 抛出结果
let data = successCallback(this.value)
// res做了三件事 改变状态 记录参数 最后执行等待中的回调
res(data)
}else if(this.status === REJECTED) {
failCallback(this.reason)
}else {
this.failCailback = failCallback
this.successCallback = successCallback
}
})
return proRes
}
}
上面的代码中,对于在回调successCallback中给出了返回值的情况做了处理,让后续then可以捕获一个成功状态,值为返回的参数。
调用如下:
let a = new promiseDemo((res, rej) => {
res(666)
}).then(res => {
console.log('res', res)
return 200
}, rej=>{
console.log('rej', rej)
}).then(res => {
console.log('res', res)
}, rej=>{
console.log('rej', rej)
})
打印结果:
3.2 返回promise对象
实际使用中还有另一种情况,将是回调并不是直接返回值,而是返回一个promise对象。
这里我们判断一个值是否是promise对象。
这个函数中res与rej函数改变的是当前then中新建立的promise对象走向,也是传递到后续then的状态走向。
这里做了一个回调函数中返回的promise对象状态到then中promise对象的状态同步。
function resolvePromise (x, res, rej) {
if(x instanceof promiseDemo){
x.then(value => res(value), reason => rej(reason))
// x.then(res, rej)
}else {
res(x)
}
}
class promiseDemo{
...
then (successCallback, failCallback) {
let proRes = new promiseDemo((res, rej) => {
if(this.status === FULFILLED) {
let data = successCallback(this.value)
// console.log(data)
// 这里调用了上面定义的函数 值是否promise对象逻辑分支
resolvePromise(data, res, rej)
}else if(this.status === REJECTED) {
failCallback(this.reason)
}else {
this.failCailback = failCallback
this.successCallback = successCallback
}
})
return proRes
}
}
调用如下:
let promise2 = new promiseDemo((res, rej) => {
res(200)
})
let a = new promiseDemo((res, rej) => {
res(666)
}).then(res => {
console.log('res1', res)
return promise2
}, rej=>{
console.log('rej', rej)
}).then(res => {
console.log('res2', res)
}, rej=>{
console.log('rej', rej)
})
打印结果:
3.3 默认参数
在then中传递的参数是可选的,当then中没有对应处理函数时,状态会自动向后传递。
promise
.then()
.then(value => console.log(value))
// ===
promise
.then(value => value)
.then(value => console.log(value))
这种效果也很容易实现,给一个默认值即可。
class promiseDemo{
...
then (successCallback = value => value, failCallback = value => value) {
...
return proRes
}
}
调用代码改为:
let a = new promiseDemo((res, rej) => {
res(666)
}).then(res => {
console.log('res1', res)
return promise2
}, rej=>{
console.log('rej', rej)
})
.then()
.then(res=>{
console.log('res2', res)
})
这种情况下,修改前的代码会报错误:
successCallback is not function
修改后的代码则会正常运行,将状态及参数后传。
打印结果:
四 错误捕获
4.1 执行器错误捕获
当执行器(promise回调函数)运行报错,应当被catch函数捕获。这是怎么实现的呢。
这里我们在回调函数中抛出一个错误。
let a = new promiseDemo((res, rej) => {
throw new Error('executor error')
res(666)
}).then(res => {
console.log('res', rej)
},rej => {
console.log('rej', rej)
})
在promise中捕捉该错误并抛到rej中,以改变状态。
class promiseDemo{
constructor(fn){
try{
fn(this.resolve, this.reject)
}catch(message){
this.reject(message)
}
}
...
}
错误就被捕捉并抛到then对应的回调中了。
打印结果:
4.2 then回调错误捕获
当执行then回调时产生的错误也应当被捕获。
class promiseDemo{
...
then (successCallback = value => value, failCallback = value => value) {
let proRes = new promiseDemo((res, rej) => {
if(this.status === FULFILLED) {
try {
let data = successCallback(this.value)
resolvePromise(data, res, rej)
}catch(message) {
rej(message) // 改变当前新的promise对象状态
}
}else if(this.status === REJECTED) {
failCallback(this.reason)
}else {
this.failCailback = failCallback
this.successCallback = successCallback
}
})
return proRes //返回新的promise对象
}
}
尝试在then的回调中抛出一个错误。
let a = new promiseDemo((res, rej) => {
res(666)
}).then(res => {
console.log('res', rej)
throw new Error('executor error')
},rej => {
console.log('rej', rej)
}).then(res => {
console.log('res2', rej)
},rej => {
console.log('rej2', rej)
})
打印结果:
刚刚我们都是在同步成功回调中添加的内容,下面补全不同状态下的处理方式。
class promiseDemo{
...
then (successCallback = value => value, failCallback = value => value) {
let proRes = new promiseDemo((res, rej) => {
if(this.status === FULFILLED) {
try {
let data = successCallback(this.value)
resolvePromise(data, res, rej)
}catch(message) {
rej(message)
}
}else if(this.status === REJECTED) {
try {
let data = failCallback(this.reason)
resolvePromise(data, res, rej)
}catch(message) {
rej(message)
}
}else {
this.successCailback = () 手把手带你实现符合Promise/A+规范的Promise