メインコンテンツまでスキップ

`Promise.prototype.finally`

· 約2分
Mathias Bynens ([@mathias](https://twitter.com/mathias))

Promise.prototype.finally を使用すると、Promise が 完了(成功または失敗が確定)した際に呼び出されるコールバックを登録できます。

ページに表示するデータを取得したいと想像してください。そして、リクエストが開始された際にローディングスピナーを表示し、リクエストが完了した際にスピナーを非表示にします。問題が発生した場合には、代わりにエラーメッセージを表示します。

const fetchAndDisplay = ({ url, element }) => {
showLoadingSpinner();
fetch(url)
.then((response) => response.text())
.then((text) => {
element.textContent = text;
hideLoadingSpinner();
})
.catch((error) => {
element.textContent = error.message;
hideLoadingSpinner();
});
};

<!--truncate-->
fetchAndDisplay({
url: someUrl,
element: document.querySelector('#output')
});

リクエストが成功した場合はデータを表示します。何か問題が発生した場合は、代わりにエラーメッセージを表示します。

いずれの場合でも、hideLoadingSpinner() を呼び出す必要があります。これまでは、then()catch() の両方のブロックでこの呼び出しを複製するしかありませんでした。Promise.prototype.finally を使用すれば、これを改善できます:

const fetchAndDisplay = ({ url, element }) => {
showLoadingSpinner();
fetch(url)
.then((response) => response.text())
.then((text) => {
element.textContent = text;
})
.catch((error) => {
element.textContent = error.message;
})
.finally(() => {
hideLoadingSpinner();
});
};

これによりコードの重複が減るだけでなく、成功/失敗の処理フェーズと後処理フェーズがより明確に分離されます。素晴らしいですね!

現在、async/await を使用すれば、Promise.prototype.finally を使わなくても同様のことが可能です:

const fetchAndDisplay = async ({ url, element }) => {
showLoadingSpinner();
try {
const response = await fetch(url);
const text = await response.text();
element.textContent = text;
} catch (error) {
element.textContent = error.message;
} finally {
hideLoadingSpinner();
}
};

asyncawait はより優れているため、標準の Promise よりもこれらを使用することを推奨します。それにもかかわらず、何らかの理由で標準の Promise を好む場合は、Promise.prototype.finally を使用することでコードをよりシンプルで明快にすることができます。

Promise.prototype.finally のサポート