Promise.finally()——解读JavaScript的全新方法

发布时间:2023-05-20

一、Promise.finally()定义及用途

Promise.finally()是ES2018新增的一个方法,可以被用于Promise链中任何位置,不管Promise实例最终的状态如何,都会执行finally中的内容。 finally()处理完毕不会改变Promise的状态,仍然返回和原来Promise状态一样的对象,常用于处理资源清理、取消网络请求时的任务取消等。

二、Promise.finally()的语法和返回

promiseInstance.finally(() => {
  //...执行的代码
});

对于链式的Promise,Promise.finally()返回的Promise还是按照上一个状态来处理。如果中途抛出异常,会影响到后面的执行。但是,finally()不会改变Promise原有状态。

三、Promise.finally()的用法介绍

1. Promise链式调用中的finally()

const promise = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('成功')
  }, 1000)
})
promise.then(res => {
  console.log(res + '后执行')
  return res
}).finally(() => {
  console.log('先执行finally()')
})

上述代码中,setTimeout设定1秒后resolve一个成功结果。在then后面链接了finally,在控制台中输出顺序如下:

  1. 任务一:成功后执行
  2. 任务二:先执行finally()

2. 处理ajax请求的finally()

axios.get('/user/12345')
  .then(function(res) {
    console.log(res.data);
  })
  .catch(function(error) {
    console.log(error);
  })
  .finally(function() {
    console.log('不管请求成功或失败,我都会被执行');
  });

上述代码中,异步的ajax调用,不管是成功还是失败,finally承担着资源释放和清理的作用。

4. Promise.all()使用finally()

Promise.all()会在所有异步操作都执行完成后才会被解析,这时就需要利用finally()的特性来处理。

const p1 = Promise.resolve(1);
const p2 = Promise.resolve(2);
const p3 = new Promise((resolve) => setTimeout(resolve, 1000, 3))
Promise.all([p1, p2, p3]).then(result => console.log(result)).finally(() => {
  console.log('我最后被执行了')
})

上述代码中,Promise.all()等待异步的操作执行完毕,Promise.all()的then()会接收一个数组,包含了全部异步完成后的结果。属性结果之后,finally()被执行,表示所有异步任务都已经完成了。

5. tslib库实现Promise.finally()

npm install tslib

导入tslib库中的polyfill使得我们可以在任何情况下使用Promise.finally()方法。如果浏览器自带的Promise没有实现finally()方法,就会导入tslib中的polyfill。

import 'tslib'
Promise.resolve(1).finally(() => {
  console.log('使用了tslib库的finally()')
})

四、Promise.finally()的局限性

Promise.finally()目前也存在着一定的局限性,在箭头函数中无法使用break、continue等语句,因为和直接用代码块的finally不同,箭头函数里的组合语句不可被终止。

五、结论

Promise.finally()是一个十分实用的方法,舒展了Promise链式调用的各个阶段,可以为清理资源、取消操作、错误处理等行为提供很好的支持。