web-dev-qa-db-ja.com

innerHTMLは非同期ですか?

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

_document.body.innerHTML = 'something';
alert('something else');
_

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

これを確認してください codepen 意味を確認してください。

setTimeout(..., 0)alertを入れても効果がないことに注意してください。 innerHTMLが実際にページを更新するためにより多くのイベントループが必要であるように見えます。

編集:

私はChromeを使用していることを忘れていました。他のブラウザはチェックしませんでした。Chromeでのみ表示されているようです。

98
apieceofbart

InnerHTMLの設定は同期的であり、DOMに加えることができるほとんどの変更も同期的です。ただし、Webページのrenderingは別の話です。

(DOMは「ドキュメントオブジェクトモデル」の略です。データの表現である「モデル」にすぎません。画面に表示されるのは、そのモデルがどのように見えるかを示す写真です。したがって、モデルを変更しても、画像を変更します-更新には時間がかかります。)

JavaScriptの実行とWebページのレンダリングは、実際には別々に行われます。簡単に言えば、最初にページ上のすべてのJavaScriptが実行され(イベントループから-詳細については this excellent video をチェックアウト)、次にafterブラウザーがユーザーに表示するWebページへの変更をレンダリングすること。これが、「ブロッキング」が非常に重要な理由です。計算集中型のコードを実行すると、ブラウザーが「JSを実行」ステップを通過して「ページをレンダリング」ステップに入り、ページがフリーズまたはスタッターします。

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

enter image description here

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

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

「パイプラインの「JavaScript」ステップで何が実行されますか?すべてのコードは毎秒60回実行されますか?」答えは「いいえ」で、JSイベントループの動作に戻ります。 JSコードは、イベントリスナー、タイムアウトなど、スタックにある場合にのみ実行されます。 前のビデオ (本当に)を参照してください。

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

129
jered

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

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

ページが変更される前にアラートが表示されるのは、ブラウザのレンダリングに時間がかかり、javascriptが行ごとに実行されるほど速くないためです。

25
d-_-b

innerHTMLプロパティは実際には同期的に更新されますが、この変更が引き起こす視覚的な再描画は非同期的に発生します。

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

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

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

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

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