一,前言
上一篇,实现了 Promise 对异步操作的支持,主要涉及以下几个点:
- 测试 Promise 对异步操作的支持; 
- 分析当前 Promise 代码问题及解决方案; 
- 使用发布订阅思想实现对异步操作的支持; 
- Promise 异步操作的测试; 
本篇,继续将实现 Promise 的链式调用;
二,前文回顾
在前几篇中,简单介绍了 Promise 的使用;翻译 Promise A+ 规范;实现简版 Promise;
上一篇,利用发布订阅模式,实现了 Promise 对异步操作的支持,主要就是以下两步:
三,提出问题
omise 的一个核心特性,就是支持链式调用;
也因此,使用 Promise 能够很好的解决异步逻辑的“回调地狱”问题;
备注:
1,测试原生 Promise
情况 1,成功回调中,返回普通值
 let promise = new Promise((resolve, reject) => {  setTimeout(() => {       // 异步操作    resolve('执行成功');    // 进入成功回调处理  }, 1000)})
promise.then((value) => {  console.log('[then1-onFulfilled]', value)  return "then1-onFulfilled:" + value  // return new Error()    // 返回普通值  // return undefined      // 返回普通值}, (reson) => {  console.log('[then1-onRejected]', reson)}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})
// [then1-onFulfilled] 执行成功// [then2-onFulfilled] then1-onFulfilled:执行成功
   复制代码
 
- 现象: 
- 1 秒后,执行了 then1 中的 onFulfilled 回调,继续 return value; 
- 然后,进入 then2 中的 onFulfilled 回调,可以获取到 then1 传递的 value; 
- 结论: 
- 成功回调中返回普通值,会进入下一个 then 的成功回调; 
情况 2,失败回调中,返回普通值
 let promise = new Promise((resolve, reject) => {  setTimeout(() => {    reject("执行失败") // 进入失败回调处理  }, 1000)})
promise.then((value) => {  console.log('[then1-onFulfilled]', value)  return "then1-onFulfilled:" + value}, (reson) => {  console.log('[then1-onRejected]', reson)  return "then1-onRejected:" + reson    // 返回普通值  // return new Error()    // 返回普通值  // return undefined      // 返回普通值}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})
// [then1-onRejected] 执行失败// [then2-onFulfilled] then1-onRejected:执行失败
   复制代码
 
- 现象: 
- 1 秒后,执行了 then1 中的 onRejected 回调,继续 return reson; 
- 然后,进入 then2 中的 onFulfilled 回调,可以获取到 then1 传递的 value;(这个 value 就是 then1 中 return 的普通值) 
- 结论: 
- 失败回调中返回普通值,会进入下一个 then 的成功回调; 
- 备注: 
- 由于每个 promise 实例的状态只能被修改一次,而示例中失败态的 promise 在第二次 then 时进入了成功的回调,说明 then1 处理完成后,返回了一个全新的 promise 实例; 
情况 3,成功回调中,抛出异常
 let promise = new Promise((resolve, reject) => {  setTimeout(() => {    resolve("执行成功")  }, 1000)})
promise.then((value) => {  console.log('[then1-onFulfilled]', value)  throw new Error("抛出异常")}, (reson) => {  console.log('[then1-onRejected]', reson)  return "then1-onRejected:" + reson}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})
// [then1-onFulfilled] 执行成功// [then2-onRejected] Error: 抛出异常
   复制代码
 
- 现象: 
- 1 秒后,执行了 then1 中的 onFulfilled 回调,抛出异常; 
- 然后,进入 then2 中的 onRejected 回调,并捕获到 then1 抛出的异常; 
- 结论: 
- 成功回调中抛出异常,会进入下一个 then 的失败回调; 
情况 4,失败回调中,抛出异常
 let promise = new Promise((resolve, reject) => {  setTimeout(() => {    reject("执行失败")  }, 1000)})
promise.then((value) => {  console.log('[then1-onFulfilled]', value)}, (reson) => {  console.log('[then1-onRejected]', reson)  throw new Error("抛出异常")}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})
// [then1-onRejected] 执行失败// [then2-onRejected] Error: 抛出异常
   复制代码
 
- 现象: 
- 1 秒后,执行了 then1 中的 onRejected 回调,抛出异常; 
- 然后,进入 then2 中的 onRejected 回调,并捕获到 then1 抛出的异常; 
- 结论: 
- 失败回调中抛出异常,会进入下一个 then 的失败回调; 
情况 5,executor 执行器中报错
如果在 executor 中就抛出了异常,还没有执行 resolve 和 reject:
备注:同步逻辑报错,非异步操作;
 let promise = new Promise((resolve, reject) => {  throw new Error("executor 同步报错") // 抛出异常  resolve("处理成功")  // 不会被执行})promise.then((value) => {  console.log('[then1-onFulfilled]', value)}, (reson) => {  console.log('[then1-onRejected]', reson)}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})// [then1-onRejected] Error: executor 同步报错// [then2-onFulfilled] undefined
   复制代码
 
- 现象: 
- executor 执行器函数中的同步操作抛出异常,进入 then1 的失败回调; 
- 由于 then1 中没有 return,相当于返回了 undefined 普通值,进入 then2 的成功处理; 
- 结论: 
- executor 同步逻辑抛出异常,进入 then 失败处理; 
总结
根据以上 5 种情况进行总结:
- Promise 的链式调用,当调用 then 方法后,将会返回一个全新的 promise 实例; 
- then 中方法(无论成功还是失败)返回普通值,都会做为下一次 then 的成功结果; 
- 执行器函数 和 then 中方法(无论成功还是失败)抛出异常,都会进入下一次 then 的失败结果; 
备注:
- 若 then 中方法返回一个 promise 实例,那么,将根据这个 promise 的状态决定执行成功还是失败的回调: 
- 成功的 promise:将返回值传递给下一个 then 的成功回调; 
- 失败的 promise:将失败原因传递给下一个 then 的失败回调; 
2,测试手写 Promise
链式调用示例(与测试原生 Promise 代码相同):
 let promise = new Promise((resolve, reject) => {  setTimeout(() => {    resolve('执行成功');  }, 1000)})
promise.then((value) => {  console.log('[then1-onFulfilled]', value)  return "then1-onFulfilled:" + value}, (reson) => {  console.log('[then1-onRejected]', reson)}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})
// TypeError: Cannot read property 'then' of undefined
   复制代码
 
现象
3,问题分析
 class Promise{  constructor(executor){    this.state = PENDING;    this.value = undefined;    this.reason = undefined;    this.onResolvedCallbacks = [];    this.onRejectedCallbacks = [];    const reslove = (value) =>{...}    const reject = (reason) =>{...}    executor(reslove, reject);  }    then(onFulfilled, onRejected){    if(this.state === PENDING){      this.onResolvedCallbacks.push(()=>{        onFulfilled(this.value) // 被调用后,没有返回新的 promise      })      this.onRejectedCallbacks.push(()=>{        onRejected(this.value) // 被调用后,没有返回新的 promise      })    }    if(this.state === DULFILLED){      onFulfilled(this.value) // 被调用后,没有返回新的 promise    }     if(this.state === REJECTED){      onRejected(this.reason) // 被调用后,没有返回新的 promise    }        // then 处理完成后,并没有继续返回 promise 对象,所以不能继续 .then  }}
module.exports = Promise; 
   复制代码
 4,解决方案
在 then 方法的回调函数执行完成后,需要获取到函数的返回值,并包装成为全新的 promise 实例;
四,Promise 链式调用的实现
获取 then 回调处理返回值
 class Promise{  constructor(executor){...}  then(onFulfilled, onRejected){      if(this.state === DULFILLED){        // 拿到回调处理的返回值        let x = onFulfilled(this.value)      }      if(this.state === REJECTED){        let x = onRejected(this.reason)        resolve(x)      }      if(this.state === PENDING){        this.onResolvedCallbacks.push(()=>{           let x = onFulfilled(this.value)           resolve(x)        })        this.onRejectedCallbacks.push(()=>{           let x = onRejected(this.reason)          resolve(x)        })      }          // 包装回调处理的返回值 x ,成为一个全新的 Promise 实例    let promise2 = new Promise((resolve, reject)=>{        // 问题:拿不到 x,不在一个作用域中    });
    // 返回新的 promise 实例,这样外部可以继续调用 .then    return promise2;  }}
   复制代码
 
问题
2,then 返回全新 promise
要解决上边的问题,就需要在 promise2 的 executor 执行器中拿到返回值 x;
 class Promise{  constructor(executor){...}  then(onFulfilled, onRejected){    // 获取成功/失败回调的返回值,并包装成为新的 Promise 实例    let promise2 = new Promise((resolve, reject)=>{      // 同步      if(this.state === DULFILLED){        // 拿到回调处理的返回值        let x = onFulfilled(this.value)        // 更改 promise2 的状态,并返回这个新的 promise 实例(即 primise2)        resolve(x)      }      // 同步      if(this.state === REJECTED){        let x = onRejected(this.reason)        resolve(x)      }      // 异步      if(this.state === PENDING){        this.onResolvedCallbacks.push(()=>{           let x = onFulfilled(this.value)           resolve(x)        })        this.onRejectedCallbacks.push(()=>{           let x = onRejected(this.reason)          resolve(x)        })      }    });
    // 返回新的 promise 实例    return promise2;  }}
   复制代码
 3,对异常的处理
executor 执行器函数和 then 中方法(无论成功还是失败)抛出异常,都会进入下一次 then 的失败结果;
只需在以下几个位置捕获异常,并执行 reject 即可:
- executor 执行器函数(在简版 Promsie 中已实现) 
- then 方法中的同步操作(DULFILLED 和 REJECTED),回调函数执行时; 
- then 方法中的异步操作(PENDING),回调函数执行时; 
 class Promise{  constructor(executor){    const reslove = (value) =>{...}    const reject = (reason) =>{...}    try{      executor(reslove, reject);     }catch(e){      reject(e)    // 捕获异常    }  }
  then(onFulfilled, onRejected){    let promise2 = new Promise((resolve, reject)=>{      if(this.state === DULFILLED){        try{          let x = onFulfilled(this.value)          resolve(x)        }catch(e){          reject(e)    // 捕获异常        }      }      if(this.state === REJECTED){        try{          let x = onRejected(this.reason)          resolve(x)        }catch(e){          reject(e)    // 捕获异常        }      }      if(this.state === PENDING){        this.onResolvedCallbacks.push(()=>{           try{            let x = onFulfilled(this.value)            resolve(x)          }catch(e){            reject(e)    // 捕获异常          }        })        this.onRejectedCallbacks.push(()=>{           try{            let x = onRejected(this.reason)            resolve(x)          }catch(e){            reject(e)    // 捕获异常          }        })      }    });
    return promise2;  }}
   复制代码
 4,测试手写 Promsie 的链式调用
 let promise = new Promise((resolve, reject) => {  setTimeout(() => {       // 异步操作    resolve('执行成功');    // 成功态,传参  }, 1000)})
promise.then((value) => {  console.log('[then1-onFulfilled]', value)  return "then1-onFulfilled:" + value}, (reson) => {  console.log('[then1-onRejected]', reson)}).then((value) => {  console.log('[then2-onFulfilled]', value)}, (reson) => {  console.log('[then2-onRejected]', reson)})
// [then1-onFulfilled] 执行成功// [then2-onFulfilled] then1-onFulfilled:执行成功
   复制代码
 
略:5 种情况与原生 Promise 表现一致;
五,执行过程分析
分析当前 Promise 的执行过程:
- 首先,应用层 new Promise 创建 promise 实例时,传入的 executor 执行器会在 constructor 中被立即执行; 
- 应用层调用 - promise.then时,传入成功/失败状态的处理逻辑;
 
- 进入 then 处理,在源码中,会先创建一个 promise2 实例;那么,promise2 的 executor 执行器也会被立即执行; 
- 此时,原本 promise 对三态的处理,就被包裹在了 promise2 的 executor 中;因此,从执行上不会受到影响,同样会被立即执行; 
- 这样,在包装 then 返回值 x 的 promise2 中,就可以拿到这个返回值 x 了! 
- 当 promise2 调用了 resolve(x),就会进入外部 - promise.then的成功回调处理,并返回一个普通值;
 
- 源码中的 promise2 中就拿到了 - promise.then的返回值 x,并通过 reslove(x) 将 promise2 的状态更新为成功态;
 
- 然后,就进入了应用层 Promise 链式调用第二个 then 的成功回调处理。。。。 
备注:
六,结尾
本篇,主要实现了 Promise 的链式调用功能,主要涉及以下几个点:
- 介绍了 Promise 链式调用,返回普通值和抛出异常的 5 种情况; 
- 分析了当前 Promise 源码的问题及解决方案; 
- Promise 链式调用的实现、功能测试、执行过程分析; 
备注:
下一篇,实现 Promise 返回值 x 的处理;
评论