43

JS のパフォーマンスに疑問があります。

次のコードがあるとします。

var divContainer = document.createElement("div"); divContainer.id="container";
var divHeader = document.createElement("div"); divHeader.id="header";
var divData = document.createElement("div"); divData.id="data";
var divFooter = document.createElement("div"); divFooter.id="footer";
divContainer.appendChild( divHeader );
divContainer.appendChild( divData );
divContainer.appendChild( divFooter );
document.getElementById("someElement").appendChild( divContainer );

このコードは、グリッドを作成する他の関数のシェルを作成するだけです。グリッドを作成するプロセスは非常に複雑で、多くの検証が必要です。現在、グリッドを埋めるために 2 つのメソッドを使用しています。1 つは配列変数で html 全体を作成します。もう 1 つは要素を作成し、それらを a に追加しますdocumentFragment

私の質問は、私が理解しているように、フラグメントを使用するときにパフォーマンスに関して本当に改善があるかどうかです-フラグメントはメモリ上の要素を管理するため、ドキュメントに添付されないため、DOM の再計算やその他の厄介なものをトリガーしません。しかし、私が変数を作成している方法では、コンテナを実際のページに追加するまで、変数はどのDOM要素にも添付されません。

したがって、以前のコードは、次のようにすべてをラップするドキュメントフラグメントを使用するよりもパフォーマンスが優れているかどうか疑問に思っていました:

var fragment = document.createDocumentFragment();
var divContainer = document.createElement("div"); divContainer.id="container";
var divHeader = document.createElement("div"); divHeader.id="header";
var divData = document.createElement("div"); divData.id="data";
var divFooter = document.createElement("div"); divFooter.id="footer";
divContainer.appendChild( divHeader );
divContainer.appendChild( divData );
divContainer.appendChild( divFooter );
fragment.appendChild( divContainer )
document.getElementById("someElement").appendChild( fragment.cloneNode(true) );

すでに述べたように、これはパフォーマンスに関する質問です。ベスト プラクティスとしてフラグメントの使用が推奨されていることは知っていますが、それを行うと単にメモリ内に新しいオブジェクトが作成され、何もしないので、この場合フラグメントを捨てることは有効だと思います。

うまくいけば、何人かのjsの第一人者/神がここに希望の光を当てて、この問題を解決してくれることを願っています.


編集:だから、私はこの問題に関連するものを探していましたが、documentFragments が必ずしもパフォーマンスの向上を意味するわけではないようです。

これは、ノードの単なる「メモリ内」コンテナです。フラグメントと a の違いは、<div>フラグメントには親がなく、DOM 上にあることはなく、メモリ内にあることです。つまり、DOM の操作がないため、フラグメントに対して行われる操作は高速です。

documentFragments に関するW3Cのドキュメントは非常に曖昧ですが、要点を言えば、誰もが好むブラウザーは実際のフラグメントを使用せず、代わりにこの MSDN ドキュメントに従って新しいドキュメントを作成します。つまり、IE のフラグメントは遅くなります。

したがって、変数に要素(たとえば)を作成するが、それをDOMに追加しない場合、要素(div、テーブルなど)などを追加し、すべての作業が完了した後(ループ、検証、要素のスタイリング)、その要素が追加されますが、フラグメントと同じですか?<div>

IEが「偽の」フラグメントを使用しているという事実を考えると、少なくともIEではそのアプローチを使用する(フラグメントではなくdivなどの要素を使用する)方が良いと思います.IEは本当に気にしませんが、テストしてください(オフィスのポリシー)。

また、次のように配列にすべての html を作成すると:

var arrHTML = ["<table>","<tr>", ....]; 

そして、これを行います

document.getElementById("someElement").innerHTML = arrHTML.join(""); 

IE の方がはるかに高速ですが、他の主要なブラウザー (FF、Chrome、Safari、Opera) は、コンテナーを使用してから追加 (フラグメントまたは div) するとパフォーマンスが向上します。

これはすべて、すべての要素を作成するプロセスが非常に高速に行われるためです。24 列で最大 20,000 行を作成するのに約 8 秒から 10 秒かかります。多くの要素 / タグですが、ブラウザーは数秒フリーズするようです。それらはすべて一度に追加されます。1つずつ追加しようとすると、地獄です。

皆さん、ありがとうございました。これは本当に面白くて楽しいものです。

4

7 に答える 7

11

通常、リフロー (ページの再描画) を避けるためにフラグメントを使用します。何かをループしてループ内に追加する場合は良いケースですが、最新のブラウザはすでにこれに最適化されていると思います。

ここでは、フラグメントをいつ使用するかの良い例を説明するために jsPerf をセットアップしました。Chrome では違いがほとんどないことに気付くでしょう (最新の最適化が機能していると思います) が、IE7 ではフラグメントなしで 0.08 ops/sec、フラグメントありで 3.28 ops/sec が得られます。

したがって、大きなデータセットをループして追加する場合、多くの要素を追加する代わりにフラグメントを使用するため、リフローは 1 回だけです。DOM に数回追加するだけの場合、または最新のブラウザーのみをターゲットにしている場合は、必要ありません。

于 2013-01-07T21:00:24.747 に答える
6

これをテストするために jspref を作成しましたが、ノード フラグメントが 2.34% 高速であるように見えます

http://jsperf.com/document-fragment-test-peluchetti

于 2013-01-07T20:11:31.837 に答える
0

私の経験では、dom 操作は通常、コール スタックが空になった後にのみ発生します。多くの dom 操作をループに入れると、ブラウザがしばらくフリーズしてから、すべてを一度に表示します。必要に応じて setTimeout を使用してスタックを中断し、より頻繁に結果を表示できます。このため、どちらの方法も同様に機能するはずです。これは実際には非常に奇妙です.1つのスタックでいくつかの要素を変更すると、変更前の状態が表示されないためです(ループ中にinnerHTMLが更新されなかった進捗通知オブジェクトにこの問題がありました-開始ステータスと最終)。

于 2013-12-25T13:21:52.497 に答える
0

OPとまったく同じ質問がありました.すべての回答とコメントを読んだ後、OPが何を求めているのかを本当に理解している人は誰もいなかったようです.

Nicola Peluchetti が投稿したテストからヒントを得て、少し修正しました。

要素を a に追加してから に追加する代わりに<div>、フラグメントテストdocumentFragmentは、documentFragment最初に<div>. <div>また、隠れたオーバーヘッド コストを回避するために、どちらのテストもコンテナと の両方を作成することから始めますが、documentFragment各テストはいずれか一方のみを使用します。

元の質問は、基本的に、 aまたは aをコンテナーとして使用してノードを1 回追加する方が速いということでした。<div>documentFragment

<div>少なくとも Chrome 49 では、 a を使用した方が速いようです。

http://jsperf.com/document-fragment-test-peluchetti/39

(現時点で)私が考えることができる唯一のユースケースdocumentFragmentは、必要なメモリが少ない場合(無視できる可能性があります)、または「コンテナに入れたくない」追加する兄弟ノードがたくさんある場合です。 " エレメント。documentFragment中身だけを残して溶ける包み紙のようなものです。

于 2016-03-16T04:50:55.370 に答える
0

<!DOCTYPE html>
<html>
<head>
    <title>TODO supply a title</title>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">

</head>
<body>
<div ms-controller='for1'>
    <ul>

    </ul>
</div>

<script>
    var ul = document.querySelector('ul');
    console.time('no fragment');
    for(var i=0;i<1000000;i++){
        var li = document.createElement('li');
        li.innerText = i;

        ul.appendChild(li);
    }
    console.timeEnd('no fragment');

    console.time('has fragment');;
    var frg = document.createDocumentFragment()
    for(var i=0;i<1000000;i++){
        var li = document.createElement('li');
        li.innerText = i+'fragment';
        frg.appendChild(li);

    }
    ul.appendChild(frg)
    console.timeEnd('has fragment');
</script>
</body>
</html>

結果はフラグメントではありません: 1615.278ms testFragment.html:36 にはフラグメントがあります: 2908.286ms

したがって、これより高速なフラグメントはありません。その理由は、クロムが何かをしたからだと思います。

于 2016-08-18T07:50:04.303 に答える