2

この質問は、DOM 構造に埋め込まれたロード データに関するものです。私はjQuery2を使用していますが、質問は他のフレームワークまたは単一のJavascriptコードに対して有効です。

次の 2 つのシナリオがあります。

  1. データが(ページと共に) 1 回読み込まれると、「データの更新」は必要ありません。

  2. 何らかのイベントによってデータが更新されたとき。

平均パフォーマンスは、いずれかで変更できます

新しい HTML と新しいデータを使用して、ページ フラグメントをリロードする必要がある、シナリオ 2 の典型的なケースを想定します。したがって、 は$('#myDiv').load('newHtmlFragment')どのような方法でも使用されます...そして、AJAX を使用する jQuery プログラマーには、「DOM ベースのデータ」をロードする方法が 2 つあります。

  • by HTML : すべてのデータを「newHtmlFragment」HTML に表現​​します。多くの段落があり、それぞれが のようになっているとし<p id="someId" data-X="someContent">...more content</p>ます。
    各 には「冗長なオーバーヘッド」data-X1="contentX1" data-X2="contentX2" ...があり、XHTML 指向のスクリプトでない場合、webservice スクリプトはエレガントではありません (私は PHP を使用しており、データは配列であり、 を使用することを好みますjson_encode)。
  • jQuery 評価による$('#myDiv').load('newHtmlFragment'): のみに 同じを使用し、<p id="someId">...more content</p>なしでdata-X。2 番目の AJAX は、jQuery スクリプトをロードし$('#someId').data(...)て評価します。したがって、これはノード選択とデータ インクルージョンのオーバーヘッドですが、大きな項目データでは、各データを JSON でエンコードできます。
  • by pure JSON : 「by jQuery」に似ていますが、2 番目の AJAX は のような JSON オブジェクトをロードしますvar ALLDATA={'someId1':{...}, 'someId2':{...}, ...}。これは、$('#myDiv p').each(function(){... foreach ... $(this).data('x',ALLDATA[id]['x']);})選択の取得などを実行する静的関数のオーバーヘッドですが、ビッグデータでは、すべてのデータを JSON でエンコードできます。

質問: 最良の選択は何ですか? シナリオまたは別のコンテキストパラメーターに依存しますか? 重大なパフォーマンスのトレードオフはありますか?

PS: 完全な答えは、パフォーマンスの問題に対処する必要があります...パフォーマンスに大きな違いがない場合、最良の選択は「最良のプログラミング スタイル」とソフトウェア エンジニアリングの考慮事項に依存します。


回答への参照として必要な場合は、より多くのコンテキスト。私の実際の問題はシナリオ 1 にあり、2 番目の選択肢である「jQuery スクリプトによる」を使用して、次を実行しています。

 $('#someId1').data({'bbox':[201733.2,7559711.5,202469.4,7560794.9],'2011-07':[3,6],'2011-08':[2,3],'2011-10':[4,4],'2012-01':[1,2],'2012-02':[12,12],'2012-03':[3,6],'2012-04':[6,12],'2012-05':[3,4],'2012-06':[2,4],'2012-07':[3,5],'2012-08':[10,11],'2012-09':[7,10],'2012-10':[1,2],'2012-12':[2,2],'2013-01':[6,10],'2013-02':[19,26],'2013-03':[2,4],'2013-04':[5,8],'2013-05':[4,5],'2013-06':[4,4]});

 $('#someId2').data({'bbox':[197131.7,7564525.9,198932.0,7565798.1],'2011-07':[39,51],'2011-08':[2,3],'2011-09':[4,5],'2011-10':[13,14],'2011-11':[40,42],'2011-12':[21,25],'2012-01':[10,11],'2012-02':[26,31],'2012-03':[27,35],'2012-04':[8,10],'2012-05':[24,36],'2012-06':[4,7],'2012-07':[25,30],'2012-08':[9,11],'2012-09':[42,52],'2012-10':[4,7],'2012-11':[17,22],'2012-12':[7,8],'2013-01':[21,25],'2013-02':[5,8],'2013-03':[8,11],'2013-04':[28,40],'2013-05':[55,63],'2013-06':[1,1]});

$('#...').data(...);   ... more 50 similar lines...  
4

2 に答える 2

3

この質問は、さまざまな側面から議論することができます。私が今思いつく 2 つは、ソフトウェア エンジニアリングとエンド ユーザー エクスペリエンスです。最初をカバーする包括的なソリューションは、後者をカバーすることもできますが、通常、そのようなソリューションを考え出すことは (そのコストのために) 不可能であり、これら 2 つはほとんど重複しません。

ソフトウェア工学の視点

この POV では、システムのさまざまな部分を可能な限り分離することを強くお勧めします。これは、データの結合を延期し、できるだけ遅く表示する方がよいことを意味します。開発者を 2 つの別々のグループに分けるのに役立ちます。サーバー側のプログラミングを知っていて、HTML (またはその他のインターフェイス レイヤー テクノロジ) がどのように機能するかを知らない人、および HTML と Javascript の経験しかない人。この部門だけでも経営陣にとってはありがたいことであり、チームワークが不可欠な大きなプロジェクトでは大いに役立ちます。また、ソフトウェア エンジニアリングが目指すシステムの保守と拡張にも役立ちます。

ユーザーエクスペリエンスの観点

前の解決策のように聞こえますが、(解決可能な) 欠点があります。質問で述べたように、ビューとデータを別々にロードする場合、それらを取得するためにサーバーに送信する必要があるリクエストの数が増えます。これには 2 つの問題があります。1 つ目は各リクエストに伴うオーバーヘッド、2 つ目はユーザーが各リクエストの応答を待たなければならない遅延です。2番目はより明白なので、それから始めましょう。インターネットと帯域幅のすべての進歩に伴い、ユーザーの期待を超えているため、この遅延を考慮する必要があります。リクエストの数を減らす 1 つの方法は、HTML フラグメント内のデータです。複数のリクエストにもオーバーヘッドの問題があります。これは HTTP プロトコルで説明できます」s ハンドシェイク (クライアント側とサーバー側の両方) と、各要求がサーバー上のセッションの読み込みにつながるという事実によって、大規模な場合はかなりの負荷になる可能性があります。繰り返しになりますが、最初のオプションがこの問題に対する答えになる可能性があります。

タイ・ブレーカー

話の両側が言ったので、どうしますか?究極のソリューションは、データとビューがクライアント上で結合され、同時にダウンロードされる両方の組み合わせです。正直なところ、私はそのようなライブラリを知りません。しかし、原則は単純です。データと空の HTML フラグメントを同じ応答内にパッケージ化し、それらを組み合わせて、ユーザーがクライアントに表示するものにするメカニズムが必要です。このソリューションは (実装するのに) コストがかかりますが、一度支払うと生涯にわたってその恩恵を受けることができるコストのようなものです。

于 2013-07-25T07:03:03.323 に答える
2

保存されたデータをどのように使用するかによって異なります。次の例を検討してください。

データベースには 300 個のアイテムがあります (過去 300 日間のサーバー アクセス ログなど)。ここで、300 個の<div>タグを表示するとします。各タグは 1 つのデータベース アイテムを表します。これを行うには 2 つのオプションがあります。

<div data-stat1="stat1" data-stat2="stat2" data-stat3="stat3">(...)</div>
<!-- again, this is repeated 300 times -->

<script>
// Example on how to show "stat1" value in all <div>s
function showStat1() {
  for(var i=1; i<=300; i+= 1) {
    var theID = '#id-' + i;
    jQuery(theID).text(jQuery(theID).data('stat1'));
  }
}
</script>

また

<div id="id-1">(...)</div>
<!-- repeat this 300 times, for all DB items -->

<script>
data = { // JSON data which is displayed in the <div> tags
  '1': ['stat1', 'stat2', 'stat3'],
  // same for all 300 items
}

// Example on how to show "stat1" value in all <div>s
function showStat1() {
  for(var i=1; i<=300; i+= 1) {
    var theID = '#id-' + i;
    jQuery(theID).text(data[i][0]);
  }
}
</script>

どのシナリオが優れていますか?

ケース 1 : データは DOM 要素に直接コード化されるため、実装が簡単なソリューションになります。私の例では、最初のコード ブロックを生成するのに必要なコードがはるかに少なく、コードがそれほど複雑ではないことがわかります。

このソリューションは、DOM 要素に直接関連するデータを格納する場合に非常に強力です (JSON と DOM の間に論理接続を作成する必要がないため)。正しい要素のデータにアクセスするのは非常に簡単です。

ただし、主な関心事はパフォーマンスです。これは進むべき道ではありません。データにアクセスするたびに、最初に JavaScript を介して正しい DOM 要素と属性を選択する必要がありますが、これにはかなりの時間がかかります。そのため、要素内のデータを読み書きする場合、シンプルさは多くのパフォーマンス オーバーヘッドをもたらします。

ケース 2 : このシナリオでは、DISPLAY を DATA ストレージから非常に明確に分離します。最初のケースに比べて大きな利点があります。

<div>A) データは表示要素と混ざってはいけません - からに切り替えたいと想像してください。<table>突然、正しいテーブル セルを正しく選択するためにすべての JavaScript を書き直す必要があります。

B) DOM ツリーを経由せずにデータに直接アクセスできる。すべての値の平均合計を計算したいとします。最初のケースでは、すべての DOM 要素をループして、それらから値を読み取る必要があります。次に、通常の配列をループするだけです

C) データは、ajax を介してロードまたは更新できます。JSON オブジェクトのみを転送しますが、データの表示に必要なすべての HTML を転送するわけではありません

D)主に上記の点により、パフォーマンスが大幅に向上します。Javascript は、DOM ツリーからデータをフィルタリングするよりも、単純な配列または (あまり複雑ではない) JSON オブジェクトを処理する方がはるかに優れています。

一般に、このソリューションは最初のケースの 2 倍以上高速です。また、明らかではありませんが、2 番目のケースの方がコーディングと保守が簡単であることもわかります。UI要素からデータを明確に分離するため、コードは単純に読みやすく理解しやすくなります...

性能比較

この JSPerf シナリオで 2 つのソリューションを比較できます: http://jsperf.com/performance-on-data-storage

さらに進める

2 番目のケースの実装では、通常、次のアプローチを使用します。

  1. UI として機能する HTML コードを生成します。JavaScript を介して HTML を生成しなければならないことがよくありますが、ページが読み込まれた後に DOM ツリーが変更されないことを前提としています。

  2. HTML の最後に、最初のページ表示用の JSON オブジェクトを含むタグを含めます。

  3. jQuery onReady イベントを介して、JSON オブジェクトを解析し、必要に応じて UI 要素を更新します (テーブルにデータを入力するなど)。

  4. データが動的に読み込まれる場合、新しいデータを含む新しい JSON オブジェクトを転送し、手順 3 とまったく同じ JavaScript 関数を使用して新しい結果を表示するだけです。

HTML ファイルの例:

<div>ID: <span class="the-id">-</span></div>
<div>Date: <span class="the-date">-</span></div>
<div>Total page hits: <span class="the-value">-</span></div>
<button type="button" class="refresh">Load new data</button>

<script src="my-function.js"></script>
<script>
function initial_data() {
    return {"id":"1", "date":"2013-07-30", "hits":"1583"};
}  
</script>

「my-function.js」ファイル:

jQuery(function initialize_ui() {
    // Initialize the global variables we will use in the app
    window.my_data = initial_data();
    window.app = {};
    app.the_id = jQuery('.the-id');
    app.the_date = jQuery('.the-date');
    app.the_value = jQuery('.the-value');
    app.btn_refresh = jQuery('.refresh');

    // Add event handler: When user clicks refresh button then load new data        
    app.btn_refresh.click(refresh_data);

    // Display the initial data
    render_data();
});

function render_data() {
    app.the_id.text(my_data.id);
    app.the_date.text(my_data.date);
    app.the_value.text(my_data.hits);
}

function refresh_data() {
    // For example fetch and display the values for date 2013-07-29
    jQuery.post(url, {"date":"2013-07-29"}, function(text) {
        my_data = jQuery.parseJSON(text);
        render_data();
    });
}

このコードはテストしていません。また、重大なエラー処理やその他の最適化が欠落しています。しかし、私が説明しようとしている概念を説明するのに役立ちます

于 2013-07-31T19:12:53.900 に答える