如何在 JavaScript 中使用 then 和 catch 与 Promise 配合使用 finally?


Javascript 异步编程使用 Promise 对象,它不会阻塞当前流程的执行,而是通知编译器尚有一些未完成的任务,并在任务完成后向系统返回信号。主要有两种可能性:Promise 对象要么成功完成,要么通过返回异常停止。为了处理来自 Promise 对象的异常,使用 catch() 方法。在 try-catch 方法中,我们还可以使用另一个名为“finally”的块。无论之前做了什么,它都会执行。对于 Promise,我们也可以使用 finally() 函数来实现相同的功能。因此,在本文中,我们的最终目标是了解如何在 Promise 中使用 then() 和 catch() JavaScript 方法与 finally 配合使用。

基本语法如下:

语法

promise
   .then(
      // do something with the result
      result => { ...}
   )
   .catch(
      // handle error
      error => { ... }
   )
   .finally(
      // do something when it has been executed successfully
      // or raised an error.
      // this work can be memory cleaning or similar task
      () => { ... }
   ) 

无论 Promise 是 fulfilled 还是 rejected,finally() 方法始终都会执行。换句话说,当调用 finally() 方法时,Promise 就会被 settled。finally() 函数在 ES2018 中首次出现。可以在 finally() 方法中放置在 Promise fulfilled 时销毁资源的代码,无论其结果如何。如果不使用 finally() 方法,我们需要在 then() 和 catch() 方法中清除我们的资源。

不使用 Finally

promise
   .then(
      // do something with the result
      result => { ...}
      // do something to clear resources
   )
   .catch(
      // handle error
      error => { ... }
      // do something to clear resources
   )

then() 和 catch() 块包含重复的代码。通过添加 finally() 块,可以轻松避免这种重复。try...catch...finally 语句中的“finally”块与 finally() 函数是相关的构造。对于同步编程中的资源清理,请使用“finally”块。而 finally() 方法则用于异步程序。

让我们来看一个示例,其中我们创建一个“Connection”类来创建数据库连接(假设)。有两种不同的方法:run() 方法用于执行查询,另一个名为 terminate() 的方法用于终止连接并清理资源。连接类定义如下:

连接类

class Connection {
   run( query ) {
      if (query != 'Add' && query != 'Modify' && query != 'Remove') {
         throw new Error( `Invalid query: ${query}`);
      }
      console.log(`Running given query: ${query}`);
      return this;
   }
   terminate() {
      console.log( 'Terminating already connected connection' )
   }
}

然后我们定义一个 connect() 方法,该方法将创建一个连接对象并返回一个 Promise 对象来处理连接。当它完成操作时,会返回一个新的连接对象,否则会引发错误。让我们看看函数定义以清楚地理解。

Connect 方法

class Connection {
   run( query ) {
      if (query != 'Add' && query != 'Modify' && query != 'Remove') {
         throw new Error( `Invalid query: ${query}`);
      }
      console.log(`Running given query: ${query}`);
      return this;
   }
   terminate() {
      console.log( 'Terminating already connected connection' )
   }
}

在最后处理场景时,使用 finally() 块。在下面的示例中:因为 success 标志设置为 true,所以 connect() 函数解析为一个新的 Connection 对象。第一个 then() 方法通过执行 Insert 查询来执行,它也返回一个 Connection 对象。连接通过 globalConnection 保存。第二个 then() 方法执行 Select 查询,它也会抛出一个错误。finally() 方法终止连接,而 catch() 方法显示错误消息。

finally 方法的使用

let globalConnection;

connect()
   .then( (connection) => {
      globalConnection = connection;
      return globalConnection.run( 'Add' );
   })
   .then( (connection) => {
      globalConnection = connection;
      return globalConnection.run( 'Remove' );
   })
   .then((connection) => {
      globalConnection = connection;
      return connection.run( 'Union' );
   })
   .catch( console.log )
   .finally( () => {
      if ( globalConnection ) {
         globalConnection.terminate();
      }
   });

完整的代码和相应的输出如下:

源代码

class Connection {
   run( query ) {
      if (query != 'Add' && query != 'Modify' && query != 'Remove') {
         throw new Error( `Invalid query: ${query}`);
      }
      console.log(`Running given query: ${query}`);
      return this;
   }

   terminate() {
      console.log( 'Terminating already connected connection' )
   }
}

const success = true;
function connect() {
   return new Promise( (resolve, reject) => {
      if ( success )
         resolve( new Connection() );
      else
         reject( 'Connection cannot be created' );
      });
   }
   let globalConnection;
   connect()
   .then( (connection) => {
      globalConnection = connection;
      return globalConnection.run( 'Add' );
   })
   .then( (connection) => {
      globalConnection = connection;
      return globalConnection.run( 'Remove' );
   })
   .then((connection) => {
      globalConnection = connection;
      return connection.run( 'Union' );
   })
   .catch( console.log )
   .finally( () => {
      if ( globalConnection ) {
      globalConnection.terminate();
   }
});

输出

Running given query: Add
Running given query: Remove
Error: Invalid query: Union
    at Connection.run (/home/cg/root/18775/main.js:4:16)
    at /home/cg/root/18775/main.js:36:25
Terminating already connected connection

使用 finally() 方法来 settled Promise,这会导致一个函数在 Promise fulfilled 或 rejected 时运行。无论 Promise 的结果如何,最好将清理资源的代码放在 finally() 方法中。

结论

在构建和分发系统到另一个平台或构建可用的平台时,异常处理是一项至关重要的任务。异常处理使用 try-catch 块。catch 块的目的是使用已建立的逻辑来处理异常。我们与它们一起使用的另一个块是我们称之为“finally”的块,无论是否发生异常,它都会执行。但只有同步系统应该使用此过程。在异步编程中,由于延迟响应,错误可能会稍后出现。为了管理异常,我们可以使用 then() 方法,它类似于 try 块。但是,在这种情况下,我们使用 finally() 函数来获得与“finally”块相同的结果。无论 Promise 是成功执行还是出现错误,此函数通常用于执行清理操作。

Arnab Chakraborty
Arnab Chakraborty

企业培训师

更新于: 2023-04-04

1K+ 阅读量

开启你的 职业生涯

通过完成课程获得认证

开始学习
广告