彻底掌握 Promise - 原生 Promise.finally 的实现(六)

32 篇文章 0 订阅
8 篇文章 0 订阅


前言

在 [\[ 彻底掌握 Promise - 原生 Promise.all 的实现(五) \]](https://blog.csdn.net/qq_40146638/article/details/124250950) 中我们已经实现了 Promise 的 resolve 方法,下面这篇文章,主要讲述 Promise.finally 方法的实现。

finally()方法返回一个Promise。在promise结束时,无论结果是fulfilled或者是rejected,都会执行指定的回调函数。这为在Promise是否成功完成后都需要执行的代码提供了一种方式。


提示:以下是本篇文章正文内容,下面案例可供参考

一、finally的使用方法

Promise.finally 方法,常用于接口请求过程中页面的 loading 状态,不论接口的返回状态是什么,都要关闭页面的 loading 状态,这样的话直接在 finally 方法中写,就不用我们在 then / catch 写两次相同的代码了。

语法

p.finally(onFinally);

p.finally(function() {
   // 返回状态为(resolved 或 rejected)
});

参数

finally 方法接收一个函数作为参数,在 Promise 执行结束后调用这个参数

具体使用方法

 let promise2 = new Promise((resolve, reject) => {
  // resolve('成功')
  reject('失败')
})
promise2.then(res => {
  console.log(res, 'resolve');
}).catch(reason => {
  console.log(reason, 'reject');
}).finally(() => {
 // 不论这个 promise 的状态是成功还是失败都会去执行这个方法
  console.log('执行了finally方法');
})

执行结果

finally的执行结果

二、实现原理

  1. 调用当前 Promise 的 then 方法返回一个新的 Promise 对象(保证链式调用)
  2. 调用 Promise 中的 resolve 方法进行返回

三、具体实现

代码实现 (完整版本会在文末贴出)

class iPromise {
	finally(callback) {
	    // 1. 调用当前 Promise 的 then 方法返回一个新的 Promise 对象(保证链式调用)
	    return this.then(
	    // 2. 调用 Promise 中的 resolve 方法进行返回
	      (value) => this.resolve(callback()).then(() => value),
	      (reason) =>
	        this.resolve(callback()).then(() => {
	          throw reason;
	        })
	    );
	  }
}

验证逻辑

let promise2 = new iPromise((resolve, reject) => {
  resolve('成功')
  // reject('失败')
})
promise2.then(res => {
  console.log(res, 'resolve2');
}, reason => {
  console.log(reason, 'reject2');
}).finally(() => {
  console.log('执行了finally方法2');
})

执行结果
finally执行结果

从执行结果中可以看到,在这个 Promise 执行完成后执行了 finally 方法中的处理函数,这里也实现了 finally 方法的实现

四、完整代码实现

const PENDING = 'pending'
const FULFILLED = 'fulfilled'
const REJECTED = 'rejected'

class iPromise {

  constructor(callback) {
    // 使用 try,catch 的方式进行函数执行的异常捕获, 放置代码的阻塞
    try {
      callback(this.resolve, this.reject)
    } catch (error) {
      this.reject(error)
    }
  }

  value = null // 成功的值
  status = PENDING // Promise 的状态默认为 pedding
  reason = null // 失败的值
  fulfilledList = [] // 保存成功的处理函数
  rejectedList = [] // 保存失败的处理函数

  resolve = (value) => {
    // 如果当前 Promise 的状态不为 pedding 的话直接返回, 不执行相应代码
    if (this.status != PENDING) {
      return
    }
    // 变更状态, 保存 resolve 中传入的值
    this.status = FULFILLED
    this.value = value
    // 使用 while 循环, 以保存成功函数的数组长度为终止条件, 使用数组的 shift 方法每次获取数组的第一个值进行执行
    while (this.fulfilledList.length) {
      this.fulfilledList.shift()()
    }
  }

  reject = (reason) => {
    // 如果当前 Promise 的状态不为 pedding 的话直接返回, 不执行相应代码
    if (this.status != PENDING) {
      return
    }
     // 变更状态, 保存 resolve 中传入的值
    this.status = REJECTED
    this.reason = reason
    // 使用 while 循环, 以保存成功函数的数组长度为终止条件, 使用数组的 shift 方法每次获取数组的第一个值进行执行
    while (this.rejectedList.length) {
      this.rejectedList.shift()()
    }
  }

  then(successCallback, errorCallback) {
    // 如果 then 方法中没有成功 / 失败的回调函数的话, 让 Promise 的值一直被传递下去, 直到最后一个then 方法, 或者then 方法中有传入回调函数
    successCallback = successCallback ? successCallback : value => value
    errorCallback = errorCallback ? errorCallback : reason => reason
    // 返回一个 Promise 对象, 让 Promise 可以链式调用
    return new iPromise((resolve, reject) => {
      // 根据 Promise 不同的状态, 执行不同的处理函数
      if (this.status == FULFILLED) {
        // 增加一个 setTimeout 的原因是把当前任务放到下一个宏任务里去执行
        // 因为处理异步可能会有问题
        setTimeout(() => {
          // 使用 try  /catch 来捕获函数执行中的异常情况, 不让程序执行卡住
          try {
            let result = successCallback(this.value)
            isiPromise(result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else if (this.status == REJECTED) {
        setTimeout(() => {
          try {
            let result = errorCallback(this.reason)
            isiPromise(result, resolve, reject)
          } catch (error) {
            reject(error)
          }
        })
      } else {
        // 如果 当前 Promise 的状态为 pedding 的话, 说明这个 promise 是异步的, 我们需要把传入的的成功 / 失败的回调函数, 保存到成功/ 失败的数组中, 等待异步返回, 执行相应的处理函数。
        this.fulfilledList.push(() => {
          setTimeout(() => {
            try {
              let result = successCallback(this.value)
              isiPromise(result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          })
        })
        this.rejectedList.push(() => {
          setTimeout(() => {
            try {
              let result = errorCallback(this.reason)
              isiPromise(result, resolve, reject)
            } catch (error) {
              reject(error)
            }
          })
        })
      }
    })

  }

  static all(arr) {
    // 创建一个保存所有结果的list
    let resultList = []
    const len = arr.length
    let index = 0
    // 返回一个 Promise 对象,让外部可以调用 then 方法获取结果
    return new iPromise((resolve, reject) => {
      // 保存结果
      function addData(key, value) {
        resultList[key] = value
        index++
        if (index == len) {
          resolve(resultList)
        }
      }
      // 循环执行传入的回调函数获取返回结果
      for (let i = 0; i < len; i++) {
        // 判断当前项,是否为一个 Promise 对象, 如果是, 调用它的then方法获取返回结果
        if (arr[i] instanceof iPromise) {
          arr[i].then(value => addData(i, value), reason => reject(reason))
        } else {
          // 是普通对象的话, 直接返回结果
          addData(i, arr[i])
        }
      }
    })
  }
  /**
   * 判断当前传入参数是否为 iPromise 对象
   * iPromise 对象直接返回
   * 普通值 生成一个新的 Promise 对象调用 新Promise 使用 resolve 方法进行返回
   */
  static resolve(value) {
    if (value instanceof iPromise) return value
    return new iPromise((resolve, reject) => {
      resolve(value)
    })
  }

  finally(callback) {
    // 1. 调用当前 Promise 的 then 方法返回一个新的 Promise 对象(保证链式调用)
    return this.then(
    // 2. 调用 Promise 中的 resolve 方法进行返回
      (value) => this.resolve(callback()).then(() => value),
      (reason) =>
        this.resolve(callback()).then(() => {
          throw reason;
        })
    );
  }
}

function isiPromise(result, resolve, reject) {
  // 判断当前 传入的result 是否为 Promise 对象,
  if (result instanceof iPromise) {
    result.then(resolve, reject)
  } else {
    resolve(result)
  }
}

总结

以上就是今天要讲的内容,本文仅仅简单介绍了 Promise.finally 静态方法的使用和实现,如有问题,敬请留言说明 ~

我们会逐步去实现 Promise 的其他静态方法
实现 Promise.catch 的静态方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值