阿里云主机折上折
  • 微信号
您当前的位置:网站首页 > Promise的finally()方法

Promise的finally()方法

作者:陈川 阅读数:20120人阅读 分类: JavaScript

Promise.prototype.finally() 的基本概念

ECMAScript 2018引入的finally()方法为Promise链式调用提供了统一处理完成/拒绝状态的入口。无论Promise最终是fulfilled还是rejected状态,finally()中的回调函数都会被执行。这个方法的主要用途是执行清理操作,比如关闭数据库连接、隐藏加载动画等。

fetch('/api/data')
  .then(response => response.json())
  .catch(error => console.error('Error:', error))
  .finally(() => {
    console.log('请求结束,无论成功或失败');
    hideLoadingSpinner();
  });

finally() 的语法特性

finally()方法接收一个回调函数作为参数,这个回调函数不接受任何参数。这是因为它不关心Promise的最终状态,只关心操作是否已完成。

promise
  .finally(() => {
    // 清理代码
  });

then()catch()不同,finally()回调中:

  1. 不会接收任何参数
  2. 返回的Promise会保持原始Promise的状态
  3. 如果抛出异常,会返回一个被拒绝的Promise

finally() 与 then/catch 的区别

finally()在行为上有几个关键区别:

  1. 状态传递finally()会将原始Promise的状态传递给链中的下一个Promise,除非在finally()回调中抛出错误。
Promise.resolve(42)
  .finally(() => {})
  .then(val => console.log(val)); // 输出42

Promise.reject('error')
  .finally(() => {})
  .catch(err => console.log(err)); // 输出'error'
  1. 返回值处理:在finally()中返回的值不会影响Promise链,除非返回的是一个Promise。
Promise.resolve('hello')
  .finally(() => 'world')
  .then(val => console.log(val)); // 输出'hello'

finally() 的常见使用场景

清理资源

let isLoading = true;

fetch('/api/data')
  .then(handleResponse)
  .catch(handleError)
  .finally(() => {
    isLoading = false;
    console.log('加载状态结束');
  });

统一日志记录

function apiCall() {
  console.log('API调用开始');
  return fetch('/api')
    .finally(() => console.log('API调用结束'));
}

组合使用案例

let connection;
openDatabase()
  .then(conn => {
    connection = conn;
    return connection.query('SELECT * FROM users');
  })
  .then(processResults)
  .catch(logError)
  .finally(() => {
    if (connection) {
      connection.close();
    }
  });

finally() 的错误处理

如果在finally()回调中抛出错误,它会覆盖原始Promise的状态:

Promise.resolve('success')
  .finally(() => {
    throw new Error('error in finally');
  })
  .then(
    val => console.log('不会执行', val),
    err => console.log('捕获错误:', err) // 输出"捕获错误: Error: error in finally"
  );

finally() 的Polyfill实现

在不支持finally()的环境中,可以用以下方式模拟:

if (!Promise.prototype.finally) {
  Promise.prototype.finally = function(callback) {
    return this.then(
      value => Promise.resolve(callback()).then(() => value),
      reason => Promise.resolve(callback()).then(() => { throw reason; })
    );
  };
}

finally() 在async/await中的使用

finally()也可以与async/await语法配合使用:

async function fetchData() {
  try {
    const response = await fetch('/api/data');
    return await response.json();
  } catch (error) {
    console.error('请求失败:', error);
    throw error;
  } finally {
    console.log('请求处理完成');
    cleanup();
  }
}

finally() 的性能考虑

虽然finally()提供了便利,但在性能关键路径上需要注意:

  1. 它增加了微任务队列的长度
  2. 在紧密循环中使用可能会影响性能
  3. 简单的状态清理可以直接放在then/catch中
// 不推荐在循环中大量使用
for (let i = 0; i < 1000; i++) {
  fetch(`/api/item/${i}`)
    .finally(cleanup); // 会产生1000个微任务
}

finally() 的浏览器兼容性

finally()在以下环境中得到支持:

  • Chrome 63+
  • Firefox 58+
  • Safari 11.1+
  • Edge 18+
  • Node.js 10+

对于旧环境,需要使用前面提到的polyfill或Babel转译。

本站部分内容来自互联网,一切版权均归源网站或源作者所有。

如果侵犯了你的权益请来信告知我们删除。邮箱:cc@cccx.cn

前端川

前端川,陈川的代码茶馆🍵,专治各种不服的Bug退散符💻,日常贩卖秃头警告级的开发心得🛠️,附赠一行代码笑十年的摸鱼宝典🐟,偶尔掉落咖啡杯里泡开的像素级浪漫☕。‌