JavaScript Promise finally()

概要: このチュートリアルでは、JavaScript Promise の finally() メソッドを使用して、Promise の結果に関わらず、Promise が確定した後にコードを実行する方法を学びます。

JavaScript Promise finally() メソッドの紹介

Promise インスタンスの finally() メソッドを使用すると、Promise が確定したときに実行される関数をスケジュールできます。

finally() メソッドの呼び出し方は次のとおりです。

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

この構文では

  • onFinally は、Promise が確定したときに非同期的に実行される関数です。

finally() メソッドは Promise オブジェクトを返し、Promise インスタンスの他のメソッドへの呼び出しを便利にチェーンできます。

finally() メソッドは ES2018 で導入されました。finally() メソッドを使用すると、Promise の結果に関わらず、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() の 2 つのメソッドがあります。

  • execute() メソッドは、insert、update、または delete クエリのみを実行します。リストにない別のクエリを渡すとエラーが発生します。
  • close() メソッドは接続を閉じ、リソースをクリーンアップします。

次の connect() 関数は、成功フラグが true に設定されている場合に、新しい Connection に解決される Promise を返します。

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)

この例では

  • success フラグが true に設定されているため、connect() 関数は新しい Connection オブジェクトに解決されます。
  • 最初の then() メソッドは Insert クエリを実行し、Connection オブジェクトを返します。globalConnection は接続を保存するために使用されます。
  • 2番目の then() メソッドは Select クエリを実行し、エラーを発行します。catch() メソッドはエラーメッセージを表示し、finally() メソッドは接続を閉じます。

2) Promsie finally() メソッドを使用して読み込みステータスを表示する

次の例では、パブリック API https://jsonplaceholder.typicode.com/posts を呼び出した後、finally() メソッドを使用して読み込み要素を非表示にする方法を示します。

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)

3番目に、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 が確定したときに実行される関数をスケジュールします。
  • Promise が確定したら、結果に関わらずリソースをクリーンアップするコードを finally() メソッドに配置するのが良い習慣です。

クイズ

このチュートリアルは役に立ちましたか?