javascriptに関するメモです。
87 views
JavaScript の await
を使った非同期処理は、処理の流れを一時停止しつつ、他の処理を並行して実行できる という特性を持っています。通常、await
を使うと、メインスレッドがその処理の完了を待たずに他の処理(UI の更新など)を進めることができます。
しかし、処理の内容によっては await
を使っても UI の更新がブロックされてしまう という問題が発生することがあります。
この記事では、
1. await
の基本的な動作
2. await
を使っても UI の更新が遅れる原因
3. その解決策
について解説します。
await
の基本的な動作通常、await
を使うと JavaScript のメインスレッドはブロックされず、他の処理(例えば UI の更新など)を先に実行できる ようになります。
await
による処理の解放async function example() {
console.log("Start");
await new Promise(resolve => setTimeout(resolve, 2000)); // 2秒待つ
console.log("End");
}
example();
console.log("After function call");
このコードの出力は次のようになります。
Start
After function call
(2秒待つ)
End
ポイント:
- example()
の await
に到達すると、2秒間待機するが、その間に "After function call"
のログが出力される。
- await
はメインスレッドをブロックしないため、他の処理が並行して進む。
この特性を利用すると、例えばボタンをクリックしたら UI をすぐ更新し、その後に重い処理を実行する というような実装が可能になります。
await
を使っても UI の更新が遅れる問題以下のコードでは、スピナーを表示するはずなのに、ボタンを押した後すぐに表示されず、長時間待った後にやっと表示される という問題が発生します。
<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>非同期処理と UI 更新</title>
<style>
#spinner {
display: none;
width: 50px;
height: 50px;
border: 5px solid lightgray;
border-top: 5px solid blue;
border-radius: 50%;
animation: spin 1s linear infinite;
}
@keyframes spin {
0% { transform: rotate(0deg); }
100% { transform: rotate(360deg); }
}
</style>
</head>
<body>
<button onclick="saveFile()">ファイルを保存</button>
<div id="spinner"></div>
<script>
async function saveFile() {
const spinner = document.getElementById("spinner");
spinner.style.display = "block"; // スピナーを表示
console.log("start");
await generateLargeFile(); // 時間のかかる処理
console.log("end");
//spinner.style.display = "none"; // スピナーを非表示
}
async function generateLargeFile() {
await new Promise(resolve => {
let a = 0;
for(let i = 0; i < 10000000000; i++) {
a = a + i;
}
console.log(a);
resolve();
});
}
</script>
</body>
</html>
await
の直前で spinner.style.display = "block";
を実行しているにもかかわらず、スピナーがすぐに表示されない。generateLargeFile()
の処理がメインスレッドを完全にブロックしてしまっているから。await
は Promise
が解決されるまで待機するが、その Promise
の処理が メインスレッドを占有する重い計算処理 だと UI の更新ができない。requestAnimationFrame
を使って UI を強制的に更新async function saveFile() {
const spinner = document.getElementById("spinner");
spinner.style.display = "block"; // スピナーを表示
await new Promise(resolve => requestAnimationFrame(resolve)); // UI を強制的に更新
console.log("start");
await generateLargeFile();
console.log("end");
spinner.style.display = "none"; // スピナーを非表示
}
setTimeout(0)
を使って UI の更新を待つasync function saveFile() {
const spinner = document.getElementById("spinner");
spinner.style.display = "block";
await new Promise(resolve => setTimeout(resolve, 0)); // UI 更新を待つ
console.log("start");
await generateLargeFile();
console.log("end");
spinner.style.display = "none";
}
await
は非同期処理を待機するが、重い計算処理があると UI の更新がブロックされる。await
でメインスレッドが解放されるが、CPU を占有する処理があると UI の更新が遅れる。requestAnimationFrame
や setTimeout(0)
を使って UI の更新を先に実行する。この問題を理解することで、JavaScript の非同期処理をより適切に扱えるようになります! 🚀
Page 14 of 16.
すぺぺぺ
本サイトの作成者。
プログラムは趣味と勉強を兼ねて、のんびり本サイトを作っています。
フレームワークはdjango。
ChatGPTで自動プログラム作成に取り組み中。
https://www.osumoi-stdio.com/novel/