如何在 Javascript 中将 finally 与 then 和 catch 结合使用?

javascriptobject oriented programmingfront end technology更新于 2024/6/29 6:19:00

Javascript 异步编程使用 promise 对象,该对象不会阻止当前流程的执行,但会通知编译器有些事情尚未完成,并且每当完成时都会向系统返回信号。主要有两种可能性。promise 对象将成功完成,或者它将通过返回异常而停止。要处理来自 promise 对象的异常,请使用 catch() 方法。在 try-catch 方法中,我们还可以使用另一个名为"finally"的块。无论之前执行了什么,它都会执行。对于承诺,我们也可以使用 finally() 函数来执行相同操作。因此,在本文中,我们的最终目标是了解如何将 finally 与 then() 和 catch() javascript 方法结合使用。

基本语法如下所示 −

语法

promise
   .then(
      // 对结果进行一些处理
      result => { ...}
   )
   .catch(
      // 处理错误
      error => { ... }
   )
   .finally(
        // 成功执行后执行某些操作
        // 或引发错误。
        // 这项工作可以是内存清理或类似的任务
      	() => { ... }
   ) 

无论承诺是被接受还是被拒绝,finally() 方法始终都会执行。换句话说,当调用 finally() 过程时,承诺就已完成。在 ES2018 中,finally() 函数首次亮相。无论承诺的结果如何,在承诺履行时销毁资源的代码都可以放在 finally() 方法中。如果不使用 finally() 方法,我们需要在 then() 和 catch() 方法中清除资源。

没有 Finally
promise
   .then(
        // 对结果进行处理
        result => { ...}
        // 进行处理以清除资源
   )
   .catch(
      // 处理错误
      error => { ... }
      // 做一些事情来清除资源
   )

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() 方法,它将创建一个连接对象并返回一个承诺对象来处理该连接。当它完成其操作时,将返回一个新的连接对象,否则将引发错误。让我们看一下函数定义以便更清楚地理解。

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() 块来处理该场景。在下面的示例中:由于成功标志设置为 true,因此 connect() 函数解析为一个新的 Connection 对象。Insert 查询通过第一个 then() 方法执行,该方法也返回一个 Connection 对象。连接通过 globalConnection 保存。Select 查询由第二个 then() 函数运行,该函数也会抛出错误。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() 方法解决承诺,该方法在承诺被履行或拒绝时运行函数。无论承诺结果如何,最好将停用资源的代码放在 finally() 过程中。

结论

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


相关文章