JavaScript Promise finally()

摘要:在本教程中,您将学习如何使用 JavaScript Promise finally() 方法在 Promise 解决后执行代码,无论其结果如何。

JavaScript Promise finally() 方法介绍

finally() 方法是 Promise 实例的方法,允许您安排一个函数在 Promise 解决时执行。

以下是调用 finally() 方法的语法

promise.finally(onFinally)Code language: JavaScript (javascript)

在此语法中

  • onFinally 是一个函数,当 Promise 解决时异步执行。

finally() 方法返回一个 Promise 对象,允许您方便地将调用链接到 Promise 实例的其他方法。

finally() 方法在 ES2018 中引入。使用 finally() 方法,您可以放置 Promise 解决时清理资源的代码,无论其结果如何。

通过使用 finally() 方法,您可以避免在 then()catch() 方法中出现重复代码,例如

promise
    .then(result => {
        // process the result
        // clean up the resources
    })
    .catch(error => {
        // handle the error
        // clean up the resources
    });
Code language: JavaScript (javascript)

现在,您可以将清理资源部分移动到 finally() 方法中,如下所示

promise
    .then(result => {
        // process the result
    })
    .catch(error => {
        // handle the error
    })
    .finally(() => {
        // clean up the resources
    });
Code language: JavaScript (javascript)

finally() 方法类似于 try...catch...finally 语句中的 finally 块。

在同步代码中,您使用 finally 块来清理资源。在异步代码中,您使用 finally() 方法代替。

JavaScript Promise finally() 方法示例

让我们看一些使用 Promise finally() 方法的示例。

1) 使用 finally() 方法清理资源

以下定义了一个 Connection

class Connection {
    execute(query) {
        if (query != 'Insert' && query != 'Update' && query != 'Delete') {
            throw new Error(`The ${query} is not supported`);
        }
        console.log(`Execute the ${query}`);
        return this;
    }
    close() {
        console.log('Close the connection')
    }
}
Code language: JavaScript (javascript)

Connection 类有两个方法:execute()close()

  • execute() 方法只执行插入、更新或删除查询。如果您传入不在列表中的其他查询,它将发出错误。
  • close() 方法关闭连接并清理资源。

以下 connect() 函数返回一个 Promise,如果成功标志设置为 true,则解析为新的 Connection

const success = true;

function connect() {
    return new Promise((resolve, reject) => {
        if (success)
            resolve(new Connection());
        else
            reject('Could not open the database connection');
    });
}
Code language: JavaScript (javascript)

以下示例使用 finally() 方法关闭连接

let globalConnection;

connect()
    .then((connection) => {
        globalConnection = connection;
        return globalConnection.execute('Insert');
    })
    .then((connection) => {
        globalConnection = connection;
        return connection.execute('Select');
    })
    .catch(console.log)
    .finally(() => {
        if (globalConnection) {
            globalConnection.`close()`;
        }
    });
Code language: JavaScript (javascript)

在此示例中

  • connect() 函数解析为新的 Connection 对象,因为 success 标志设置为 true
  • 第一个 then() 方法执行 Insert 查询并返回 Connection 对象。globalConnection 用于保存连接。
  • 第二个 then() 方法执行 Select 查询并发出错误。catch() 方法显示错误消息,finally() 方法关闭连接。

2) 使用 Promsie finally() 方法显示加载状态

以下示例展示了如何使用 finally() 方法在调用公共 API https://jsonplaceholder.typicode.com/posts 后隐藏加载元素。

index.html

<!DOCTYPE html>
<html lang="en">

    <head>
        <meta charset="UTF-8">
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <title>JavaScript finally - API Call with Loading State</title>
        <script src="app.js" defer></script>
    </head>

    <body>
        <button id="fetchButton">Fetch Data</button>
        <div id="loading" style="display: none">Loading...</div>
        <div id="content" style="display: none"></div>
    </body>

</html>Code language: JavaScript (javascript)

app.js

document.getElementById('fetchButton').addEventListener('click', () => {
  const loadingElement = document.getElementById('loading');
  const contentElement = document.getElementById('content');

  // Show loading and hide content
  loadingElement.style.display = 'block';
  contentElement.style.display = 'none';

  // Make the API call to get posts
  fetch('https://jsonplaceholder.typicode.com/posts')
    .then((response) => response.json())
    .then((posts) => {
      // Render the posts
      const renderedPosts = posts
        .map((post) => {
          return `
            <h1>${post.title}</h1>
            <p>${post.body}</p>
            `;
        })
        .join('');

      // Show the posts
      contentElement.innerHTML = renderedPosts;
    })
    .catch((error) => {
      // Handle any errors
      contentElement.innerHTML = `<p>Failed to load data</p>`;
    })
    .finally(() => {
      // Hide loading and show content
      loadingElement.style.display = 'none';
      contentElement.style.display = 'block';
    });
});
Code language: JavaScript (javascript)

工作原理。

首先,向按钮添加一个点击事件处理程序

document.getElementById('fetchButton').addEventListener('click', () => {
   // ...
});Code language: JavaScript (javascript)

其次,显示加载元素并隐藏内容元素

const loadingElement = document.getElementById('loading');
const contentElement = document.getElementById('content');

 // Show loading and hide content
loadingElement.style.display = 'block';
contentElement.style.display = 'none';Code language: JavaScript (javascript)

第三,使用 Fetch API 调用 API 并渲染帖子

fetch('https://jsonplaceholder.typicode.com/posts')
  .then((response) => response.json())
  .then((posts) => {
    // Render the posts
    const reenderedPosts = posts
      .map((post) => {
        return `
            <h1>${post.title}</h1>
            <p>${post.body}</p>
            `;
      })
      .join('');

    // Show the posts
    contentElement.innerHTML = reenderedPosts;
  })
  .catch((error) => {
    // Handle any errors
    contentElement.innerHTML = `<p>Failed to load data</p>`;
  })
  .finally(() => {
    // Hide loading and show content
    loadingElement.style.display = 'none';
    contentElement.style.display = 'block';
  });Code language: JavaScript (javascript)

finally() 方法中,隐藏加载元素并显示内容元素。

总结

  • finally() 方法安排一个函数在 Promise 解决时执行,无论成功或失败。
  • 最佳实践是在 Promise 解决后将清理资源的代码放在 finally() 方法中,无论其结果如何。

测验

本教程对您有帮助吗?