如何在 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+ 閱讀量

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告

© . All rights reserved.