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

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

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

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

Q&A

解決済

3回答

513閲覧

コールバック関数外の処理のタイミングについて

yuki84web

総合スコア1857

JavaScript

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

0グッド

0クリップ

投稿2018/02/21 06:39

javascript

1function animate() { 2 $('#hoge').fadeTo(2000, 1, function() { 3 $('#foo').hide(); 4 $('#bar').fadeTo(1000, 1); 5 }); 6}

上記のように書くと、
"#hoge"のフェードインが完了した後に
"#foo"が非表示になると同時に"#bar"がフェードインします。
しかし、

javascript

1function animate() { 2 $('#hoge').fadeTo(2000, 1, function() { 3 $('#foo').hide(); 4 }); 5 $('#bar').fadeTo(1000, 1); 6}

上記のように書くと、
"#hoge"のフェードインと同時に"#bar"がフェードインします。
何故このようになるのでしょうか?

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

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

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

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

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

guest

回答3

0

JavaScriptはシングルスレッドで動作するので、特殊な機能を使わなければ同時に2つの処理を走らせる事は不可能です。
そして、document.writeでHTMlを無理やり修正できる(非推奨です)存在があるので、
ブラウザはJavaScriptを走らせるとページの動作を一時的にストップさせます。
なのでwhileで無限ループを作って無理やりスリープさせるとブラウザ全体が停止する大惨事に繋がります。

まぁ、スリープしたり待ったりすることが出来ない言語と考えてください。
その代わり、イベントという特定の条件を満たした場合、処理を再開する仕組みを持っています。

代表的なのがjQueryでも多くの場面で使われているsetTimeout
「○○ミリ秒経過したら引数に渡した関数を実行しておいてね」とお願いするだけで、その場では関数を実行する事なくスルーしてしまいます。

そしてJavaScriptは今実行している処理が全て終了した後、
「あ、そういえばsetTimeoutで登録されたんだったよな…タイムアウトになってる物はあるかな?」と探しに行きます。
タイムアウトになっているモノを見つければ、登録済みの関数を実行するわけですね。
このような仕組みで擬似的にスリープや○○完了を待つという事を実現しているのです。

まぁシングルスレッドで同時に同じ処理は1個しか走りませんが、
JavaScriptは高速で1秒間に何万もこういった処理を次々と捌いてくれますので、
ほぼ並列処理の世界であり「非同期処理」と呼ばれています。


JavaScriptにはアニメーションという機能は存在しません。
そこで、テレビアニメやゲームの画面のようにパラパラ漫画を作る事によって実現させています。

短い時間で何度もDOM要素を掴んでCSSのwidthやleft等の値を書き換えて瞬間移動させる処理を繰り返すわけですね。
TVアニメが秒間15回前後ですが、ゲームは秒間30/60回画面を更新するものが多いです。
ざっくり大体1/60秒のタイミングで動けば滑らかなんじゃないでしょうか。

JavaScript

1var fn = function () { 2 // 経過時間に応じてDOMのプロパティを弄って瞬間移動させる処理 3 setTimeout(fn, 17); // 1/60秒は約16.6ミリ秒です 4}

jQueryは便利なライブラリですが、中で動いているコードはネイティブのJavaScript。
アニメーションという機能は上記のものと同じくsetTimeoutを利用しながら何度も要素を瞬間移動させてるわけです。

setTimeoutを呼ぶという事はその場では何も処理は実行しませんね。
質問文の内容通り、アニメーションの次の処理は質問文のコードを全て舐め終わってから更に17ミリ秒経った後に実行されます。
アニメーション完了時に走ってほしい処理も当然アニメーションが終わった後です。


見分け方は簡単です。
ライブラリや組み込み関数でコールバック関数を求めるものは全てこの仕組みです。
「終わったら、引き続き処理するよ」というやつですね。

何故ならば普通の計算等を行い待ってくれる同期的な処理の場合、
完了後の処理はその次の行に書けば自動的に待ってくれますよね。
つまり、コールバック関数など使う必要はなく、単に複雑で面倒な書き方をしているだけです。

私はsetTimeoutに登録するだけだぞ、終わってから実行してほしい処理があったら教えてくれよ!
…という意図があるからこそ、コールバック関数を引数にくださいと言っているのです。

分かりやすいように簡単なコードを用意しました。

JavaScript

1// コールバック関数を求めるけど同期実行になる例 2var fn = function (cb) { 3 cb(); 4} 5fn(function(){ 6 console.log(1); 7}); 8console.log(2); 9// 1 -> 2 の順に表示される 10 11// 非同期になる専用関数を利用する例 12var fn2 = function (cb) { 13 setTimeout(cb, 0); // 0ミリ秒後実行だとしても一旦処理完了を待つので必ず後になる 14} 15fn2(function(){ 16 console.log(1); 17}); 18console.log(2); 19// 2 -> 1 の順に表示される 20 21// 直接使っても非同期 22setTimeout(function(){ 23 console.log(1); 24}, 0); 25console.log(2); 26// 2 -> 1 の順に表示される

【おまけ】

他にもこういう風に実行を予約はするけど、その場では何もしない機能は沢山あります。

代表例がaddEventListenerという機能です。
これはDOMツリーの描画が終わった瞬間、ユーザーがブラウザでマウスをクリックした時、スクロールした時…などなどのタイミングを指定して、
第二引数として渡したコールバック関数を実行させるという作りです。
その場で実行させようがないので当然非同期です。

先程アニメーションはsetTimeoutで表現すると書きましたが、
最近のブラウザでは約1/60秒に一度のブラウザの描画更新タイミングと同時に処理を挟み込むrequestAnimationFrameが用意されています。
setTimeoutより滑らかにレンダリング出来るので、jQueryでもrequestAnimationFrameが実装されているか否かを判定しながら優先的に扱ってくれるそうです。
まぁsetTimeoutと同じく短い時間待たなければ実行出来ないので当然非同期。

Ajaxを司っているXMLHttpRequestもHTTP通信が終わった後に実行しますのでこの類に含まれますね。
HTTP通信は遅く、同期的に待たせると平気で数秒ブラウザが固まるのでこれも非同期で使うのが基本です。

投稿2018/02/21 11:48

miyabi-sun

総合スコア21158

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

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

yuki84web

2018/02/22 08:42

とても詳しい解説ありがとうございます。実は他の処理部分にはsetTimeoutが大量に使われていました。今後、似たような処理を書く際に参考にさせて頂きます。
guest

0

ベストアンサー

アニメーションが非同期処理だからです。

.fadeToなどのメソッドを実行すると、アニメーションを開始しただけで戻ってきて、アニメーションの進行を待ちません。なので、次に実行したアニメーションも、ほぼ同じタイミングで進んでいきます。

投稿2018/02/21 06:47

maisumakun

総合スコア145121

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

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

0

jQueryの「コールバック関数」はその名の通り、当該処理が終わってから実行されます。それ以外はほぼ並列で実行が始まります。

投稿2018/02/21 06:46

kei344

総合スコア69364

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問