Node には、非同期コードをよりクリーンで制御しやすくするユーティリティがいくつか用意されています。古いコールバック API を Promise に変換したり、操作をキャンセルしたり、複数の非同期タスクを協調させたりできます。
promisify — コールバック API を Promise に変換する
{ promisify } ;
fs ;
readFileAsync = (fs.);
data = (, );
Node には、非同期コードをよりクリーンで制御しやすくするユーティリティがいくつか用意されています。古いコールバック API を Promise に変換したり、操作をキャンセルしたり、複数の非同期タスクを協調させたりできます。
{ promisify } ;
fs ;
readFileAsync = (fs.);
data = (, );
promisify は標準的な (args..., (err, result) => {}) 形式のコールバック関数をラップして await できるようにします。Promise 以前の古いライブラリに役立ちます。(多くの組み込みモジュールは現在、fs/promises のように Promise 版を直接提供しています。)
const controller = new AbortController();
// キャンセル可能な操作に signal を渡す
const promise = fetch("https://api.example.com", { signal: controller.signal });
// キャンセルする(例: タイムアウトやユーザーのページ遷移時)
setTimeout(() => controller.abort(), 5000); // 5 秒後に中断
try {
await promise;
} catch (err) {
if (err.name === "AbortError") console.log("request cancelled");
}
AbortController は実行中の操作(fetch、タイマー、ストリーム、多くのライブラリ)をキャンセルする標準的な手段を提供します。タイムアウトや、結果がもう不要になったときの無駄な処理を避けるために不可欠です。
// 並列に実行し、すべての完了を待つ(いずれかが reject すると即座に失敗する)
const [a, b, c] = await Promise.all([getA(), getB(), getC()]);
// すべてを待ち、各結果またはエラーを取得(短絡しない)
const results = await Promise.allSettled([getA(), getB()]);
// 最初に決着(resolve または reject)したものが勝つ
const fastest = await Promise.race([fetchPrimary(), fetchBackup()]);
// 最初に成功(fulfill)したもの(成功するまで reject は無視する)
const first = await Promise.any([source1(), source2()]);
これらのコンビネータは一般的なパターンを表現します。並列実行して待つ場合は all、失敗にかかわらずすべての結果が必要な場合は allSettled、タイムアウト / 最速優先には race、フォールバックのソースには any です。
import { setTimeout as sleep } from "timers/promises";
await sleep(1000); // 手動で Promise でラップせずに遅延を await できる
これらのユーティリティは、実際の非同期 Node コードをよりクリーンで堅牢にします。promisify はレガシーなコールバック API を async/await へ橋渡しし、AbortController はキャンセルとタイムアウトを追加し(ハングした操作や無駄な操作を防ぐ)、Promise コンビネータ(all/allSettled/race/any)は一般的な協調パターンを簡潔かつ正確に表現します。
これらを知っていれば、並列処理、キャンセル、フォールバックを自前で作り直す代わりにエレガントに扱えます。これらは、自明でない非同期アプリケーションにおける共通のニーズです。