阿里云主机折上折
  • 微信号
Current Site:Index > The finally() method of Promise

The finally() method of Promise

Author:Chuan Chen 阅读数:20123人阅读 分类: JavaScript

Basic Concept of Promise.prototype.finally()

Introduced in ECMAScript 2018, the finally() method provides a unified entry point for handling both fulfilled and rejected states in Promise chains. Regardless of whether the Promise ultimately resolves or rejects, the callback function in finally() will be executed. This method is primarily used for cleanup operations, such as closing database connections or hiding loading animations.

fetch('/api/data')
  .then(response => response.json())
  .catch(error => console.error('Error:', error))
  .finally(() => {
    console.log('Request completed, regardless of success or failure');
    hideLoadingSpinner();
  });

Syntax Characteristics of finally()

The finally() method takes a callback function as an argument, which does not accept any parameters. This is because it does not care about the final state of the Promise, only whether the operation has completed.

promise
  .finally(() => {
    // Cleanup code
  });

Unlike then() and catch(), the finally() callback:

  1. Does not receive any parameters
  2. Returns a Promise that maintains the original Promise's state
  3. If an exception is thrown, it returns a rejected Promise

Differences Between finally() and then/catch

finally() has several key behavioral differences:

  1. State Propagation: finally() passes the original Promise's state to the next Promise in the chain unless an error is thrown in the finally() callback.
Promise.resolve(42)
  .finally(() => {})
  .then(val => console.log(val)); // Outputs 42

Promise.reject('error')
  .finally(() => {})
  .catch(err => console.log(err)); // Outputs 'error'
  1. Return Value Handling: Values returned in finally() do not affect the Promise chain unless a Promise is returned.
Promise.resolve('hello')
  .finally(() => 'world')
  .then(val => console.log(val)); // Outputs 'hello'

Common Use Cases for finally()

Resource Cleanup

let isLoading = true;

fetch('/api/data')
  .then(handleResponse)
  .catch(handleError)
  .finally(() => {
    isLoading = false;
    console.log('Loading state ended');
  });

Unified Logging

function apiCall() {
  console.log('API call started');
  return fetch('/api')
    .finally(() => console.log('API call ended'));
}

Combined Usage Example

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

Error Handling in finally()

If an error is thrown in the finally() callback, it overrides the original Promise's state:

Promise.resolve('success')
  .finally(() => {
    throw new Error('error in finally');
  })
  .then(
    val => console.log('Will not execute', val),
    err => console.log('Caught error:', err) // Outputs "Caught error: Error: error in finally"
  );

Polyfill Implementation of finally()

In environments that do not support finally(), it can be simulated as follows:

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; })
    );
  };
}

Using finally() with async/await

finally() can also be used with async/await syntax:

async function fetchData() {
  try {
    const response = await fetch('/api/data');
    return await response.json();
  } catch (error) {
    console.error('Request failed:', error);
    throw error;
  } finally {
    console.log('Request processing completed');
    cleanup();
  }
}

Performance Considerations for finally()

While finally() provides convenience, there are performance considerations in critical paths:

  1. It increases the length of the microtask queue
  2. Heavy usage in tight loops may impact performance
  3. Simple state cleanup can be placed directly in then/catch
// Not recommended for heavy use in loops
for (let i = 0; i < 1000; i++) {
  fetch(`/api/item/${i}`)
    .finally(cleanup); // Generates 1000 microtasks
}

Browser Compatibility for finally()

finally() is supported in the following environments:

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

For older environments, use the polyfill mentioned earlier or transpile with Babel.

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

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

Front End Chuan

Front End Chuan, Chen Chuan's Code Teahouse 🍵, specializing in exorcising all kinds of stubborn bugs 💻. Daily serving baldness-warning-level development insights 🛠️, with a bonus of one-liners that'll make you laugh for ten years 🐟. Occasionally drops pixel-perfect romance brewed in a coffee cup ☕.