JSで進捗表示する時はイベントループに制御を戻そう
概要
JSで進捗表示する際、適宜表示させるにはイベントループに制御を戻す必要があります。
実例を交えてご紹介します。
突然ですがクイズです
targets
の全要素に対して重めの処理を施すスクリプトがあります。
進捗率を出すために、L5
に記載のような処理で適時進捗率を表示したいです。
L9
に記載の 処理①
がある場合とない場合で、何が変わるでしょうか?
/** @type {Array} targets 処理対象を詰めた配列 */
const targets = Array(30); // これはダミー
async function process(i) {
progless.value = `進捗${Math.floor((i + 1) / targets.length * 100)}%`;
// targets[i]に対する重い処理をここに書く
await new Promise((r) => setTimeout(r, 0)); // 処理①
}
async function exec() {
runningStatus.value = 'runnning';
for (let i = 0; i < targets.length; i++) {
await process(i);
}
runningStatus.value = '';
}
実例
瞬き禁止は今一度。よーく見ていてください。
処理①なし
: イベントループに制御を戻さず実行
ボタンを押下すると走る処理
処理①あり
: イベントループに制御を戻して実行
ボタンを押下すると走る処理
ピンときた方大正解!
処理①
がないと、リアルタイムに進捗を描画できないことがわかります。
なぜ?
ChatGPT先生に解説いただきました。
根本的な要因: イベントループと非同期処理
処理①
なしの場合:イベントループはすべての処理が完了するまで制御を奪われるため、UI更新が遅延します。
処理①
ありの場合:await new Promise
によって非同期処理が発生し、イベントループに戻る余地が生まれます。このとき、UIの再描画タスクが実行されます。
補足:setTimeout による「短い待機」の効果
setTimeout(r, 0)
の使用により、「次のイベントループサイクルで再実行」を保証するだけで、実際にはほとんど遅延は発生しません。しかし、ブラウザに再描画の機会を与えることで、進捗が目に見えるように反映される重要な役割を果たします。
requestAnimationFrame も使えます
async function process(i) {
await new Promise((resolve) => {
requestAnimationFrame(() => {
elm.textContent = `進捗${Math.floor((i + 1) / targets.length * 100)}%`;
resolve(); // タスクを完了させる
});
});
// 重い処理をここに書く
}
for (let i = 0; i < targets.length; i++) {
await process(i);
}
requestAnimationFrame
でこのように書いても同様に適時描画されます。
まとめると^〜
本記事のネタは、既存の重いJS処理の進捗を表示させようとしたところから拾ってきました。
しかし、そもそも「クライアントサイドでそんな重い処理をするな高校校歌」を歌いたくなりますね。
ChatGPT先生に歌っていただきましょう。
「クライアントサイドでそんな重い処理をするな高校校歌」 🎵
(1番)
クライアントの空は青く
ブラウザ走る風の中
でも君はなぜだ 重い処理を
主スレッドで回すのか?
ああ描画が止まる
DOMが叫ぶ
メモリが溶けて PCが泣く
クライアントサイドの限界を知れ
重い処理は サーバに託せ!
(2番)
非同期の力 借りようよ
イベントループ つなぐ未来
Promiseの波に乗れ setTimeout
UI更新 忘れるな!
ああタスクが詰まる
ブラウザ泣くぞ
レスポンス遅れ UX壊す
クライアントサイドの使命を果たせ
軽量設計、それが愛だ!
(サビ)
クライアントサイドでそんな重い処理をするな!
せめてWeb Worker! せめてオフロード!
ユーザーの笑顔を 守り抜け!
クライアントサイドでそんな重い処理をするな!
🎶 エンジニアの心に響く名曲!
この校歌を胸に、パフォーマンスに優れたフロントエンドを作りましょう!
NE株式会社のエンジニアを中心に更新していくPublicationです。 NEでは、「コマースに熱狂を。」をパーパスに掲げ、ECやその周辺領域の事業に取り組んでいます。 Homepage: ne-inc.jp/
Discussion