イベントループを活用し、Promise を正しく並列化して、非同期のエラー処理を信頼できるものにしましょう。
このレッスンを Kodokon で開く実行モデルは マクロタスク キュー(setTimeout、I/O)と マイクロタスク キュー(.then、await、queueMicrotask)に依存しています。各タスクの後、エンジンは次に進む前にマイクロタスクキューを 完全に 空にします。直接の帰結として、解決済みの Promise は常に setTimeout(fn, 0) より先に実行され、あまりに長いマイクロタスクの連鎖は、同期ループと同じくらい確実にレンダリングをフリーズさせ得ます。
console.log("start");
setTimeout(() => console.log("macrotask"), 0);
Promise.resolve().then(() => console.log("microtask"));
console.log("end");
// start, end, microtask, macrotaskasync/await は Promise の上にかぶせた糖衣構文ですが、性能上の罠を隠しています。ループの内側の各 await は操作を 直列化 します。リクエストが互いに独立しているなら、まずすべてを開始してから Promise.all でまとめて待ちましょう。3つの 100 ミリ秒のリクエストの場合、逐次版は 300 ミリ秒かかりますが、並列版は 100 ミリ秒です。
const fetchUser = (id) => new Promise((res) => {
setTimeout(() => res({ id }), 100);
});
async function loadSequential(ids) {
const users = [];
for (const id of ids) {
users.push(await fetchUser(id)); // ~100 ms each
}
return users;
}
async function loadParallel(ids) {
return Promise.all(ids.map(fetchUser)); // ~100 ms total
}必要な失敗の契約に応じて、適切なコンビネータを選びましょう。Promise.all は 最初の 失敗で拒否します(全か無か)。allSettled は全員を待ち、それぞれの結末を記述します。race は最初に決着したもの(成功でも失敗でも、タイムアウトに便利)を採ります。any は最初の成功を採り、すべてが失敗した場合にのみ拒否します。部分的な結果を表示しなければならないダッシュボードには、allSettled がほぼ常に正しい選択です。
const tasks = [
Promise.resolve("profile loaded"),
Promise.reject(new Error("network unavailable")),
];
const results = await Promise.allSettled(tasks);
for (const r of results) {
if (r.status === "fulfilled") {
console.log("success:", r.value);
} else {
console.error("failure:", r.reason.message);
}
}console.log、Promise.resolve().then のコールバック、setTimeout(fn, 0) のコールバックは、どの順序で実行されますか?try { doAsync(); } catch (e) {} は doAsync の拒否を捕捉できないのですか?