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

Promise.prototype.finally()

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

Basic Concept of Promise.prototype.finally()

ECMAScript 2018 (ES9) introduced the Promise.prototype.finally() method, which allows a specified callback function to be executed regardless of whether the Promise succeeds or fails. This method addresses the previous issue of having to repeat the same code in both then() and catch().

The finally() method takes a callback function as an argument. This callback does not accept any parameters because it does not care whether the Promise's final state is fulfilled or rejected.

const promise = new Promise((resolve, reject) => {
  // Asynchronous operation
});

promise
  .then(result => { /* Handle success */ })
  .catch(error => { /* Handle failure */ })
  .finally(() => { /* Executes whether the Promise succeeds or fails */ });

Behavioral Characteristics of finally()

The finally() method has several important behavioral characteristics worth noting:

  1. The callback function does not receive any parameters because it does not care about the Promise's final state.
  2. It returns a new Promise with the same value as the original Promise.
  3. If the callback function throws an error or returns a rejected Promise, the error will be propagated.
  4. In a Promise chain, finally() does not alter the original Promise's value.
Promise.resolve(2)
  .then(x => x * 2)
  .finally(() => { console.log('Calculation complete') })
  .then(x => console.log(x)); // Output: Calculation complete followed by 4

Promise.reject(new Error('Failure'))
  .catch(e => { console.log(e.message); return 'Recovery value' })
  .finally(() => console.log('Cleanup work'))
  .then(x => console.log(x)); // Output: Failure, Cleanup work, Recovery value

Differences from then/catch

finally() differs from then() and catch() in several key ways:

  1. Parameter Handling: then() and catch() callbacks receive the Promise's result or error, while finally() does not receive any parameters.
  2. Impact on Return Value: The return value of finally()'s callback does not affect the Promise chain unless an error is thrown.
  3. Execution Timing: finally() ensures execution after the Promise completes, regardless of success or failure.
// then/catch require repeating code
somePromise
  .then(result => {
    doSomething(result);
    cleanup();
  })
  .catch(error => {
    handleError(error);
    cleanup();
  });

// Using finally is more concise
somePromise
  .then(result => doSomething(result))
  .catch(error => handleError(error))
  .finally(() => cleanup());

Practical Use Cases

finally() is useful in various scenarios:

  1. Resource Cleanup: Cleanup work that must be performed regardless of success or failure.
  2. Loading State Management: Hiding loading indicators.
  3. Database Connections: Closing database connections.
  4. Animation Control: Stopping loading animations.
let isLoading = true;

fetch('/api/data')
  .then(response => response.json())
  .then(data => processData(data))
  .catch(error => showError(error))
  .finally(() => {
    isLoading = false;
    document.getElementById('loading').style.display = 'none';
  });

Implementation Principle and Compatibility

The implementation of finally() can be thought of as a special then() call:

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

In terms of compatibility, modern browsers and Node.js support finally(), but older environments may require a polyfill. Libraries like core-js or es6-promise can be used to provide support.

Common Pitfalls and Considerations

When using finally(), keep the following points in mind:

  1. Errors in Callback Functions: If an error is thrown in the finally() callback, it will override the previous Promise state.
  2. Return Values: The return value of finally()'s callback is ignored unless it returns a rejected Promise.
  3. Asynchronous Cleanup: If cleanup work needs to be done asynchronously, a Promise should be returned.
// Bad example: Errors in finally override the original result
Promise.resolve('Success')
  .finally(() => { throw new Error('finally error') })
  .catch(e => console.log(e.message)); // Output: finally error

// Correct handling of asynchronous cleanup
somePromise
  .finally(() => {
    return asyncCleanup(); // Return a Promise to ensure asynchronous cleanup completes
  });

Integration with Other Asynchronous Features

finally() can be effectively combined with other asynchronous features:

  1. async/await: Using finally in async functions.
  2. Promise.all: Using it with combination methods like Promise.all().
  3. Cancelable Promises: Using finally for cleanup in cancellation logic.
async function fetchData() {
  try {
    const response = await fetch('/api/data');
    return await response.json();
  } catch (error) {
    console.error('Failed to fetch data:', error);
    throw error;
  } finally {
    console.log('Request completed');
  }
}

// Combining with Promise.all
Promise.all([promise1, promise2])
  .then(results => processResults(results))
  .finally(() => console.log('All operations completed'));

Performance Considerations

While finally() provides convenience, performance-sensitive scenarios require consideration:

  1. Microtask Queue: finally() increases the length of the microtask queue.
  2. Memory Usage: Multiple finally() calls in long Promise chains can increase memory overhead.
  3. Error Handling: Additional finally() callbacks may complicate error handling.
// Avoid unnecessary finally chains
// Not recommended
promise
  .finally(() => {})
  .finally(() => {})
  .finally(() => {});

// Recommended
promise.finally(() => {
  // Consolidate all cleanup logic
});

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

如果侵犯了你的权益请来信告知我们删除。邮箱: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 ☕.