質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

Q&A

解決済

4回答

411閲覧

非同期処理について (setTimeout)

nkfr26

総合スコア1

JavaScript

JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

非同期処理

非同期処理とは一部のコードを別々のスレッドで実行させる手法です。アプリケーションのパフォーマンスを向上させる目的でこの手法を用います。

0グッド

2クリップ

投稿2024/07/05 05:42

html

1<!DOCTYPE html> 2<html lang="ja"> 3 4<head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7</head> 8 9<body> 10 <button>sleep</button> 11 <script src="main.js"></script> 12</body> 13 14</html>

js

1// 引数で渡された時間 (ミリ秒) ループする 2const sleep = (ms) => { 3 const sleepStartTime = new Date(); 4 while (new Date() - sleepStartTime < ms) { } 5}; 6 7// ボタンがクリックされたとき、4000ミリ秒待機する 8const click = () => { 9 sleep(4000); 10}; 11 12const button = document.querySelector("button"); 13button.addEventListener("click", click); 14 15const startTime = new Date(); 16setTimeout(() => console.log(new Date() - startTime), 2000);

リロード直後にボタンを押したとき、コンソールには4000前半の数字が出力されます。
このコードを書いたとき、
200ミリ秒でボタンを押す → 4000ミリ秒待機 → 残りの1800ミリ秒待機 → 6000が出力
となるのではないかと思っていました。これはsetTimeoutの仕様が原因ですか?

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答4

0

ベストアンサー

200ミリ秒でボタンを押す → 4000ミリ秒待機 → 残りの1800ミリ秒待機 → 6000が出力となるのではないかと思っていました。

なりません。これには2つの要因があります。

  • setTimeoutは、「何ミリ秒後に動かす」というリストに登録する処理を行う、というイメージです。積極的に待ち続けるという処理を行うものではありません。
  • JavaScriptはシングルスレッドなので、while()で回し続けるようなビジーループをかけると、他のハンドラ類も一切動かなくなります。

ということで、タイムラインとしては以下のようになります。

0ミリ秒→setTimeoutでタイマーが登録される
200ミリ秒→ボタンを押してビジーループがスタート
2秒→setTimeoutのタイマーが時間を迎えるけど、ビジーループがまわり続けているので動作しない
4.2秒→ビジーループが終了したことで、ようやくsetTimeoutのハンドラが動作

投稿2024/07/05 05:54

maisumakun

総合スコア145899

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

maisumakun

2024/07/05 05:55

ビジーループをかけると、ブラウザ内の操作が一切反応しなくなります。実用サイトでやるべきではありません。
guest

0

setTimeout() は、setTimeout() が呼ばれた後の指定ミリ秒後に指定コードを実行しようとします。そのタイミングでCPUが忙しければイベントループに戻った瞬間に実行されます。

質問者さんの想定のような挙動がほしいなら、setInterval()requestAnimationFrame() が一定回数呼ばれたら処理をする、ということをする必要があります。

投稿2024/07/05 05:57

int32_t

総合スコア21574

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

非同期処理を同期したいならpromiseとの連携が必須です

html

1<script> 2const sleep = async(ms) => { 3 console.log(await new Promise(resolve=>setTimeout(()=>resolve('done'),ms))); 4} 5document.addEventListener("click",async ({target})=>{ 6 if(target.matches("#btn1")){ 7 const startTime = new Date(); 8 await sleep(4000); 9 setTimeout(() => console.log(new Date() - startTime), 2000); 10 } 11 if(target.matches("#btn2")){ 12 const startTime = new Date(); 13 sleep(4000); 14 setTimeout(() => console.log(new Date() - startTime), 2000); 15 } 16}); 17</script> 18 19<button id="btn1">sleep1</button> 20<button id="btn2">sleep2</button>
  • sleep1は4秒まってdone、その後2秒待ってconsoleで表示されるので約6秒
  • sleep2はsleep処理が非同期なので2まってconsoleされ、その後2秒(計4秒)待ってdoneされます

なおsetTimeout自体worker処理なので、任意にworkerでwhlieを回しても同等のことは可能です

投稿2024/07/05 07:02

yambejp

総合スコア116363

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

0

回答ではありません

皆さん言われてるとおりなので、これは補足です。
あまり詳しい解説ではないし(英語にすると僅かに詳しくなる)、例外もあるので、取っ掛かりの参考までに。

並行モデルとイベントループ - JavaScript | MDN
https://developer.mozilla.org/ja/docs/Web/JavaScript/Event_loop#%E3%83%A1%E3%83%83%E3%82%BB%E3%83%BC%E3%82%B8%E3%81%AE%E8%BF%BD%E5%8A%A0

投稿2024/07/05 06:37

編集2024/07/05 06:40
退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問