首先我们看下链式调用的例子
function testP1(){
return new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('p1')
},2000)
})
}
function testP2(){
return new MyPromise((resolve,reject)=>{
setTimeout(()=>{
resolve('p2')
},2000)
})
}
testP1().then((res)=>{
console.log(res);
return testP2()
}).then((res)=>{
console.log(res);
})
可以看到我们在传入给第一个promise的then函数的回调函数中、返回了一个promise,同时又执行了一个then函数。
也就是说
我们的then函数最终返回了一个promise。那么。我们是不是让我们的then函数变成
then((onFulfilled,onRejected){
return onFulfilled
}
就好了?
如果我们只是想实现这样的结构。当然是没有问题的
function test1(){
return {
a(){
console.log('a');
}
}
}
function test2(){
return {
test(fn){
return fn()
}
}
}
test2().test(()=>{
return test1()
})
.a() // a
最终输出a
但是可惜的是。
1、我们的promise是异步的 我们的then函数现在是
then(onFulfilled,onRejected){
if(this.state==='fulfilled'){
onFulfilled(this.value)
}
if(this.state==='rejected'){
onRejected(this.reason)
}
if(this.state==='pedding'){
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
}
这个样子的
2、如果不返回promise呢?
第一个问题决定了,我们的then函数的回调函数会在return之后执行
也就是说如果我们要按照上面的写法得话,那么就是
then(onFulfilled, onRejected) {
let promise2
if (this.state === 'fulfilled') {
promise2 = onFulfilled(this.value)
}
if (this.state === 'rejected') {
promise2 = onRejected(this.reason)
}
if (this.state === 'pedding') {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
return promise2
}
那么问题就很明显了
我们没有办法去处理pedding的时候的promise2 因为他是被压入了一个栈中,在resolve之后才能执行,所以,我们的promise2 在大部分情况下都是 undefined
也就是说 我们不能直接返回 return 的 nextPromise
注意、我这里没有说promise2 而是nextPromise 为什么要进行区分?因为promise2是我们定义在class Promise的then函数里面的,而nextPromise是未知的。
从而我们进而得出了一个问题、无法直接返回nextPromise 那么我们nextThen怎么进行处理呢?
在代码
function testP1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function testP2() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 2000)
})
}
testP1().then((res) => {
console.log(res);
return testP2()
}).then((res) => {
console.log(res);
})
中、我们的第二个then函数到底是怎么回事?到底是谁在执行?
那么我们就有了两个问题
1、返回什么
2、怎么处理then函数
先来处理第一个
首先,必须是返回一个promise 因为promise才有then函数、得出代码
then(onFulfilled, onRejected) {
let promise2 = new MyPromise((resolve, reject) => {
})
if (this.state === 'fulfilled') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
if (this.state === 'pedding') {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
return promise2
}
那么这个函数的exector是什么呢?
此外 我们应该注意到一个问题、then函数
then函数不是在延迟之后才执行的,而是立刻执行的,但是他把then函数的参数—某个回调函数压入了一个函数栈中,等到时机进行执行。
我们可以进行一次debugger
观察此图
可以发现
1、输出了一个 then 标记
2、回调函数栈 onFulfilledCallbacks 跟 onRejectedCallbacks 中存在函数了
3、promise2中空空如也
那么我们执行下一操作
可以发现又执行了一个 then函数 进行了输出 且此时没有输出 p1 也就是说第一个then函数中的回调函数没有执行
为了进行区分 我们对我们的测试代码进行部分修改
function testP1() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function testP2() {
return new MyPromise((resolve, reject) => {
setTimeout(() => {
resolve('p2')
}, 2000)
})
}
testP1().then((res1) => {
console.log(res1);
return testP2()
}).then((res2) => {
console.log(res2);
})
可以看到我们修改了我们的 then的回调函数 第一个传入的参数是res1 第二个参数是res2
重新debugger一次
可以看到第一步我们的函数是第一个 回调函数是res1 => {}
而点击 继续
变成了 res2=>{}
此时是返回的promise2
我们执行这样的操作为了证明什么呢?
为了证明
1、第二个then函数 其实是在第一个promise返回的promise2中 而不是在nextPromise中
2、then函数的执行是同步的 也就是说 ,当我们一个链式操作写完的时候 所有的then函数会按照流式执行,而不会进入异步队列中 等到上一个then函数中的回调函数执行后 才执行下一个then函数
如图
所以说,此时nextPromise的then中是没有回调函数的,也不会去执行,而nextPromise 我们以为要执行的回调函数其实是在promise2中
那么我们给出解决方案
1、在恰当的时候 执行 nextPromise的then函数
2、在nextPromise 的resolve执行的时候,控制promise2的resolve执行,从而执行promise2中then函数接受到得回调函数
对于第一个问题
必然是在 上一个promise的then函数的回调函数执行之后才执行 为什么?因为nextPromise就是前一个then函数的回调函数的返回值~~ 所以 必然是在之后执行
对于第二个问题
当nextPromise的resolve执行之后,会调用 nextPromise中的then函数的第一个参数 也就是onFulfilled 所以我们可以在这里 执行promise2的resolve函数 因此我们必须把promise2的resolve函数传递给nextPromise的then函数的回调函数中或者说在这里执行
因此 对于代码
then(onFulfilled, onRejected) {
console.log('then');
let promise2 = new MyPromise((resolve, reject) => {
})
if (this.state === 'fulfilled') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
if (this.state === 'pedding') {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
return promise2
}
应该改成
then(onFulfilled, onRejected) {
console.log('then');
let promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
if (this.state === 'pedding') {
this.onFulfilledCallbacks.push(onFulfilled)
this.onRejectedCallbacks.push(onRejected)
}
})
return promise2
}
那么我们再来执行下一步操作
如何在第一个then之后的回调函数执行之后执行 nextPromise的then 这个并不难,拿到值执行就好了,给出以下的代码
then(onFulfilled, onRejected) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
onFulfilled(this.value)
}
if (this.state === 'rejected') {
onRejected(this.reason)
}
if (this.state === 'pedding') {
this.onFulfilledCallbacks.push(()=>{
let x =onFulfilled(this.value)
if(typeof x === 'object'){
if(typeof x.then === 'function'){
x.then.call(x,res=>{
resolve(res)
})
}
}
})
this.onRejectedCallbacks.push(onRejected)
}
})
return promise2
}
我们先只观察pedding中的onFulfilledCallbacks 我们队原来的onFulfilledCallbacks进行了进一步的封装不再是单纯的执行内容了,而是先执行onFulfilledCallbacks后再执行 nextPromise的回调函数,并将resolve放入then中执行,所以在执行nextPromise的resolve的时候就会执行nextPromise的then的回调函数,从而执行promise2的resolve函数
同时对于reject也应该执行类似的操作 所以我们可以提成一个函数
resolvePromise
then(onFulfilled, onRejected) {
let promise2 = new MyPromise((resolve, reject) => {
if (this.state === 'fulfilled') {
let x =onFulfilled(this.value)
resolvePromise(promise2,x,resolve,reject)
}
if (this.state === 'rejected') {
let x =onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject)
}
if (this.state === 'pedding') {
this.onFulfilledCallbacks.push(()=>{
let x =onFulfilled(this.value)
resolvePromise(promise2,x,resolve,reject)
})
this.onRejectedCallbacks.push(()=>{
let x =onRejected(this.reason)
resolvePromise(promise2,x,resolve,reject)
})
}
})
return promise2
}
function resolvePromise(promise2,x,resolve,reject){
if(typeof x === 'object'){
if(typeof x.then === 'function'){
x.then.call(x,res=>{
resolve(res)
})
}
}
}
同时 我们还要处理一下如果返回值不是promise的情况 在Promise中
function testP1() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('p1')
}, 2000)
})
}
function testP2(res) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(res+'p2')
}, 2000)
})
}
testP1().then((res1) => {
console.log('res1',res1); // res1 p1
// return testP2(res1)
return '1'
}).then((res2) => {
console.log('res2',res2); // res2 1
})
返回的参数会作为进行传递
所以
function resolvePromise(promise2,x,resolve,reject){
if(typeof x === 'object'){
if(typeof x.then === 'function'){
x.then.call(x,res=>{
resolve(res)
})
}else{
resolve(x)
}
}else{
resolve(x)
}
}
至此 我们的链式调用就基本完成了。
当然 这个并不是很符合PromiseA+的规范~或者说也没有打算按照规范走了
因为我感觉很多写promise的实现的文章,有的时候我就会在想,他们自己在写的时候真的是知道为啥要这么做吗?当然对于大神来说肯定知道,不过看到很多的实现都是一种~好像是按照大神的代码写一遍,但是却没有什么不同,这样大神虽然懂,但是去看的时候,却很难懂,等你看懂了,就花费了很长的时间了,那么效率就很低,因为大神的代码可能涉及到了其他的东西,不是逐步递进的,看起来有的时候就会有理解上的困难qwq
最后附上我在学习的过程中参考的两个博客吧,他们写的很详细,我感觉也就没有必要再去画蛇添足了,我相信你看了我的博客以后再看他们的就会好理解很多了。