innerHTMLは非同期ですか?


101

私は自分を馬鹿にしないでほしいと思いますが、次の2行のコードで何が起こっているのかを理解しようとしています。

document.body.innerHTML = 'something';
alert('something else');

私が観察しているのは、HTMLが更新される前(または更新されているがページが更新/再描画されていないなど)の前にアラートが表示されることです。

このコードペンをチェックして、私の意味を確認してください。

でも置くことに注意してくださいalertにはsetTimeout(..., 0)役立ちません。innerHTML実際にページを更新するには、より多くのイベントループが必要のようです。

編集:

Chromeを使用していることを忘れて、他のブラウザをチェックしていません。Chromeでのみ表示されるようです。それにもかかわらず、なぜそれが起こっているのか私はまだ興味があります。


4
これはChromeの典型です。
トリンコット2017年

2
@trincotありがとう!私がChromeを使用していることを忘れてしまったので、尋ねる前に他のブラウザーを試しませんでした。参考資料はありますか?
apieceofbart 2017年

16
DOMの変更は同期的です。DOMのレンダリングは、JavaScriptスタックがクリアされた後に実際に行われます。developers.google.com/web/fundamentals/performance/rendering JavaScript>スタイル>レイアウト>ペイント>コンポジット。(少なくともChromeの場合。他のブラウザも同様です。)
2017年

2
単なる推測:アラートがブロックされていると、ブラウザーが再描画ステップに到達できなくなるため、DOMが変更されている間は、まだ再描画することはできません。もう一度、ただの推測です。
zzzzBov 2017年

2
@qbolecこのビデオをチェックしてください:youtu.be/r8caVE_a5KQ
apieceofbart 2017年

回答:


130

innerHTMLの設定は同期的であり、DOMに対して行うことができるほとんどの変更も同様です。ただし、Webページのレンダリングは別の話です。

(DOMは「ドキュメントオブジェクトモデル」を意味します。これは単なる「モデル」であり、データを表しています。ユーザーが画面に表示するのは、そのモデルの外観の画像です。したがって、モデルを変更しても、瞬時に画像を変更します-更新にはしばらく時間がかかります。)

JavaScriptの実行とWebページのレンダリングは、実際には別々に行われます。- (チェックアウトイベントループからページを実行に最初にすべてのJavaScriptの、単純化し、それを置くために、この優れたビデオその後、詳細についての)とした後ブラウザが参照するには、ユーザーのためのWebページへの変更をレンダリングします。これが、「ブロック」が非常に重要である理由です。計算集約型のコードを実行すると、ブラウザが「JSの実行」ステップを通過して「ページのレンダリング」ステップに入り、ページがフリーズまたは途切れることになります。

Chromeのパイプラインは次のようになります。

ここに画像の説明を入力してください

ご覧のとおり、すべてのJavaScriptが最初に発生します。次に、ページがスタイル設定、レイアウト、ペイント、および合成されます-「レンダリング」。このパイプラインのすべてがすべてのフレームを実行するわけではありません。どのページ要素が変更されたか、またどのように再レンダリングする必要があるかによって異なります。

注:alert()も同期しており、JavaScriptステップ中に実行されます。そのため、Webページへの変更が表示される前にアラートダイアログが表示されます。

ここで、「ちょっと待ってください、パイプラインの「JavaScript」ステップで正確に何が実行されますか?すべてのコードは1秒あたり60回実行されますか?」答えは「いいえ」で、JSイベントループの動作に戻ります。JSコードは、それがスタック内にある場合にのみ実行されます-イベントリスナー、タイムアウトなどから。前のビデオを見てください(本当に)。

https://developers.google.com/web/fundamentals/performance/rendering/


1
答えてくれてありがとう。イベントループなどの詳細については知っていました。このパイプラインは完全に理にかなっていますが、例が示すように、すべてのブラウザーで同じではありません。他のブラウザが警告を表示する前にページが再描画されるのを待つ場合、ボタンをクリックしてから警告自体を表示するまでに大幅な遅延が発生する可能性があります。後で遊んでみます。
apieceofbart 2017年

@apieceofbart他のブラウザも、ユーザーが警告ウィンドウを処理するまでJavaScriptを停止しながら、ページを非同期で再描画するだけです。再描画が行われるのを待つ必要があるという意味ではありません。
JonasSchäfer2017年

27

はい、同期しています。これが機能するためです(さあ、コンソールに入力してください):

document.body.innerHTML = 'text';
alert(document.body.innerHTML);// you will see a 'text' alert

ページが変化する前にアラートが表示されるのは、ブラウザのレンダリングに時間がかかり、JavaScriptが1行ずつ実行されるほど高速ではないためです。


ありがとう、確認しました。ただし、それはChromeに固有の何かである必要があります-他のブラウザーで期待どおりに機能します。それとも、JavaScriptの次の行に移動するためにページが再描画されるのを待つのは、彼らの欠陥ですか?
apieceofbart 2017年

3
アラートには正しいテキストが表示されますか?(text私の例では)同期であるかどうかの質問に答えます。ブラウザのレンダリングとJavascriptの実行はリンゴとオレンジです:)
d -_- b

問題はありませんが、質問とは関係ありません
apieceofbart

1
あなたの質問は文字通り「innerHTMLは非同期ですか?」です。値が同期した直後に使用できる場合、違いますか?私は、innerHTMLの同期品質ではなく、ページのレンダリングについてもっと質問するつもりだと思います。
d -_- b

8
はい、質問は明らかに間違っていましたが、何を質問したらいいのかわかりませんでした。もし私が正しい答えを知っていたら、おそらく答えを見つけたでしょう。とにかく意地悪という意味ではありませんでした。とにかく答えてくれてありがとう!
apieceofbart 2017年

6

innerHTML実際のプロパティは、同期して更新さんが、この変更が生じることが視覚的に再描画が非同期的に起こります。

DOMの視覚的なレンダリングはChromeでは非同期であり、現在のJavaScript関数スタックがクリアされ、ブラウザーが自由に新しいイベントを受け入れるまでは発生しません。他のブラウザーは、JavaScriptコードとブラウザーのレンダリングを処理するために別のスレッドを使用する場合や、アラートが別のイベントの実行を停止しているときに、一部のイベントを優先させる場合があります。

これは2つの方法で確認できます。

  1. for(var i=0; i<1000000; i++) { }アラートの前に追加した場合は、ブラウザに再描画を実行するための十分な時間が与えられていますが、関数スタックがクリアされていない(addまだ実行されている)ため、そうではありません。

  2. alert非同期setTimeout(function() { alert('random'); }, 1)でを遅延させると、再描画プロセスはsetTimeoutによって遅延された関数より先に進みます。

    • タイムアウトを0に設定した場合、これは機能しません。おそらくChromeが0、他のイベントよりも前に(または少なくとも再描画イベントより前に)タイムアウトにイベントキューの優先順位を与えるためです。

答えてくれてありがとう!setTimeout(func, 1)毎回うまくいかないこともありますので、このビデオを確認してください:youtu.be/r8caVE_a5KQ
apieceofbart 2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.