在手写Promise笔记(上)我们已经得到了一个可用的手写Promise,不过过一阵子再来看,还是发现有很多地方不记得了,下面补上结合手写代码的Promise用法以及图解,加强记忆。
都是个人理解如果有错误,欢迎提出
Promise的基本用法
new myPromise((resolve, reject) => {
resolve("成功");
}).then(
msg => {
console.log(msg);
},
error => {
console.log(error);
}
);
上面的代码是一个最普通的Promise用法,then
方法中对应的第一个是onFulfilled
方法,第二个是onRejected
方法。此时Promise的内部代码是同步的,resolve("成功")
会直接更改,当前Promise的状态,在then
方法会执行以下代码
let promise = new myPromise((resolve,reject) => {
if(this.status === myPromise.PENDING) {
......
}
// 这里判断状态,必须是解决状态的情况才会执行onFulfilled函数,否则会出现状态没改变也执行的情况
if(this.status === myPromise.FULFILLED) {
setTimeout(() => {
this.parse(promise,onFulfilled(this.value),resolve,reject)
}, 0)
}
if(this.status === myPromise.REJECT) {
......
}
})
return promise
}
会把当前返回的promise
以及传入的onFulfilled
,这里的resolve
以及reject
都是新new出来的Promise自带的。在parse
函数中会做以下的处理
parse(promise,result,resolve,reject) {
if(promise === result) {
// 这里的判断用于限制Promise.then不能返回自身
throw new TypeError('aaa')
}
// 使用try..catch也是为了捕获then中出现的错误,只有写了catch才会有错误信息输出
try {
// 这里的更改主要是针对Promise的内部函数的异步处理
// 通过instanceof来判断result是否是通过myPromise实现的,从而确定是否是返回的Promise
if (result instanceof myPromise) {
// 如果是Promise的话,目的还是要改变Promise的状态,并且返回值
// 此时 result 是一个Promise
// 这里相当于重新执行了一次返回的Promise,递归
result.then(resolve,reject)
} else {
// 普通值直接返回
resolve(result)
}
} catch (error) {
// then的异步处理中出现error就交给onRejected处理
// 同时这里的处理函数从onRejected改为reject,相当于把错误代码交给了
// 最后一个then来处理
reject(error)
}
}
这样上面那个最简单的Promise的使用就相当于
-
resolve("成功")
,变更当前Promise的状态为fulfilled,函数内的setTimeout异步函数挂起 - 进入
then
方法,此时的状态为fulfilled,所以进入this.parse(promise,onFulfilled(this.value),resolve,reject)
代码,因为当前的onFulfilled
方法为一个简单的打印,不是返回Promise,那么就直接使用新返回的Promise的resolve
方法执行,此时的this.value='成功'
,那么就相当于调用msg => {console.log(msg)}
,之前resolve
挂起的定时器异步任务开始执行,callback
为空,所以无结果。
相当于then中最后执行的结果如下
let promise = new myPromise((resolve,reject) => {
setTimeout(() => {
this.parse(promise,onFulfilled(this.value),resolve,reject)
}, 0)
})
return promise
这里我不太清楚,返回的Promise
和parse
之间的运行关系,希望以后有机会找大佬请教下
Promise内的异步操作
假设Promise内的操作是异步的,这种情况还是挺常见的,例如异步获取数据之类的。
let p = new myPromise((resolve, reject) => {
setTimeout(() => {
resolve("成功")
}, 0);
}).then(
msg => {
console.log('promise' + msg);
},
error => {
console.log(error);
}
)
console.log('我先执行')
输出的结果是我先执行---promise成功
这里就会涉及到JavaScript中的EvenLoop
,直接看手写代码,这里只解释成功的部分,失败的部分原理一样。
在resolve方法中
resolve(value) {
// 这里需要增加一个判断,如果当前Promise的状态为pending的时候,才能进行状态更改和处理
if(this.status === myPromise.PENDING) {
this.status = myPromise.FULFILLED
this.value = value
setTimeout(() => {
this.callbacks.map(callback => {
callback.onFulfilled(value)
})
})
}
}
在then方法中
if(this.status === myPromise.PENDING) {
this.callbacks.push({
onFulfilled: value => {
this.parse(promise,onFulfilled(value),newresolve,newreject)
},
onRejected: reason => {
this.parse(promise,onRejected(reason),newresolve,newreject)
},
})
}
如果Promise本体中的方法是异步的,当函数开始的时候,内部的定时器挂起,此时定时器是一个宏任务,异步执行,之后执行到then
方法,方法内判断到当前的状态pending
,那么就会将传入的onFulfilled
和onRejected
通过parse
处理后保存起来。
此轮同步循环结束,执行之前挂起的定时器,开始循环callback
中的onFulfilled
方法,并且执行,完成异步输出的结果。
Promise的链式调用
Promise链式调用的前提就是前一个then返回的是一个Promise,并且下一个then对应的状态总是成功的
let p = new myPromise((resolve, reject) => {
// resolve("成功")
reject("失败")
}).then(
msg => {
console.log('promise' + msg);
return '成功22'
},
error => {
console.log(error);
return '失败22'
}
)
.then(
msg => {
console.log('promise2' + msg);
},
error => {
console.log(error);
}
)
上面的代码无论第一个使用的是resolve还是reject,第二个then都是走console.log('promise2' + msg)
上面例子代码的运行流程
- 首先
new myPromise
的时候首先同步执行reject("失败")
,此时当前Promise的状态为rejected - 进入第一个
then
,因为判断当前状态时rejected,会执行
if(this.status === myPromise.REJECT) {
setTimeout(() => {
this.parse(promise,onRejected(this.value),newresolve,newreject)
}, 0)
}
此时setTimeout
挂起第一个异步程序,这里我们把它叫做定时1
- 然后第一个
then
返回了一个新的Promise,叫做newPromise,并且通过他连接上下一个then
- 在这个newPromise中,
resolve
和reject
函数都没有执行,所以当前的newPromise的状态还是pending,在then
中判断状态,就把第二个then
中的两个函数通过parse
处理后存起来。 - 以上同步任务都处理完成了,会进入Promise中的定时1,开始执行其中的异步程序。
setTimeout(() => {
this.parse(promise,onRejected(this.value),newresolve,newreject)
}, 0)
这里的newresolve
和newreject
是返回的newPromise中的resolve
和reject
函数,在parse
会判断第一个then返回的onRejected
是不是Promise,如果不是就用传入的newresolve
来执行
相当于执行了
newresolve(msg => {
console.log('promise' + msg);
return '成功22'
})
- newPromise的内部
resolve
执行的就是resolve('成功22')
接受'成功22'这个参数,并且更改newPromise的状态为resolved,此时newPromise的之前保存函数callbacks
也不为空了,循环执行之前保存的onFulfilled
函数 - 上面的过程就实现了
then
的链式调用
then中返回一个Promise的情况
如果 then 返回的是一个promise,那么需要等这个promise,那么会等这个promise执行完,promise如果成功,就走下一个then的成功,如果失败,就走下一个then的失败。
let p2 = new myPromise((resolve,reject) => {
reject('失败了')
})
new myPromise((resolve, reject) => {
resolve("成功")
// reject("失败")
}).then(
msg => {
console.log('promise' + msg);
return p2
},
error => {
console.log(error);
return '失败22'
}
)
.then(
msg => {
console.log('promise2' + msg);
},
error => {
console.log('then2'+ error);
}
)
这里主要通过
parse
来进行操作的,可以看最上面parse
的全部代码这里只放部分了
if (result instanceof myPromise) {
result.then(resolve,reject)
}
这里传入的result就是前一个then方法的onFulfilled(this.value)
或者onRejected(this.value)
msg => {
console.log('promise' + msg);
return p2
},
对应到上面代码就是这段,返回的p2,作为result传入了parse
,再通过instanceof
来判断是否是由myPromise
创建的,就是判断是不是一个Promise。
之后直接调用了p2.then()
,所以下一个then
相当于是p2.then().then()
这种形式,第一个then
发生值传递,直接给第二个then
,且p2中是使用reject
方法,所以是走onRejected()
方法输出