2

这个问题是关于加载嵌入到 DOM 结构中的数据。我正在使用 jQuery2,但这个问题对任何其他框架或单个 Javascript 代码都有效。

有两种情况:

  1. 当数据加载一次(与页面)时,不需要“刷新数据”。

  2. 当某个事件刷新数据时。

平均性能可以用一个或另一个来改变

假设场景 2 的典型案例,其中必须使用新 HTML 和新数据重新加载页面片段。所以,$('#myDiv').load('newHtmlFragment')将被以任何方式使用......而且,对于使用 AJAX 的 jQuery 程序员来说,有两种方法可以加载“基于 DOM 的数据”:

  • 通过 HTML:将所有数据表示为“newHtmlFragment”HTML。假设有很多段落,每个都喜欢<p id="someId" data-X="someContent">...more content</p>
    每个 都有一些“冗长的开销”,data-X1="contentX1" data-X2="contentX2" ...如果 webservice 脚本不是面向 XHTML 的脚本(我使用的是 PHP,我的数据是一个数组,我更喜欢使用json_encode),那么它对于 webservice 脚本来说并不优雅。
  • 通过 jQuery 评估:仅使用相同$('#myDiv').load('newHtmlFragment') 的 for <p id="someId">...more content</p>,没有data-X. 第二个 AJAX 加载一个类似的 jQuery 脚本$('#someId').data(...)并对其进行评估。所以这是一个开销,对于节点选择和数据包含,但是对于大项目数据,每个数据都可以用 JSON 编码。
  • by pure JSON:类似于“by jQuery”,但第二个 AJAX 加载 JSON 对象,如var ALLDATA={'someId1':{...}, 'someId2':{...}, ...}. 因此,这是执行诸如$('#myDiv p').each(function(){... foreach ... $(this).data('x',ALLDATA[id]['x']);})检索选择之类的静态函数的开销,但是对于大数据,所有数据都可以由 JSON 编码。

问题:最好的选择是什么? 这取决于场景或其他上下文参数?是否存在显着的性能权衡?

PS:完整的答案需要解决性能问题...如果没有显着的性能差异,最佳选择取决于“最佳编程风格”和软件工程考虑。


更多上下文,如果您需要作为参考答案。我的实际问题是在场景 1 中,我正在使用第二个选择“通过 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

这个问题可以从不同的方面来讨论。我现在能想到的两个是软件工程和最终用户体验。首先涵盖的综合解决方案也可以涵盖后者,但通常不可能提出这样的解决方案(由于其成本),这两者几乎没有重叠。

软件工程的观点

在这个 POV 中,强烈建议系统的不同部分尽可能隔离。这意味着您最好推迟数据的结合并尽可能晚地查看。它可以帮助您将开发人员分成两个不同的组;那些了解服务器端编程但不知道 HTML(或任何其他接口层技术)如何工作的人,以及只对 HTML 和 Javascript 有经验的人。仅这个部门就对管理层来说是一种祝福,它对团队合作至关重要的大型项目有很大帮助。它还有助于系统的维护和扩展,这是软件工程的所有目标。

用户体验角度

尽管之前的解决方案听起来不错,但它也有(可解决的)缺点。正如您在问题中提到的,如果我们要分别加载视图和数据,它会增加我们必须发送到服务器以检索它们的请求数量。它带来了两个问题,首先是每个请求带来的开销,其次是延迟用户必须等待每个请求得到响应。第二个更明显,所以让我们从它开始。随着互联网和带宽的所有进步,我们的用户超出预期迫使我们考虑这种延迟。减少请求数量的一种方法是您的首选:HTML 片段中的数据。多个请求也有开销问题。这可以通过 HTTP 协议来解释' s 握手(在客户端和服务器端),并且每个请求都会导致在服务器上加载会话,这在很大程度上可能是相当可观的。所以你的第一个选择可能是这个问题的答案。

决胜局

故事的双方都说了,然后呢?最终的解决方案是数据和视图在客户端结合,但同时下载。老实说,我不知道这样的图书馆。但原理很简单,您需要一种机制来将数据和空 HTML 片段打包在同一个响应中,并将它们组合成用户将在客户端看到的内容。这个解决方案是昂贵的(实施),但它是一种一旦支付了你就可以终生受益的成本。

于 2013-07-25T07:03:03.323 回答
2

这取决于您将如何使用存储的数据。考虑这个例子:

例子

您在数据库中有 300 个项目(例如过去 300 天的服务器访问日志)。现在您要显示 300 个<div>标签,每个标签代表一个数据库项。现在有两个选项可以做到这一点:

<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>假设您想要从

B) 无需遍历 DOM 树即可直接访问数据。想象一下,您想计算所有值的平均总和。在第一种情况下,您需要循环所有 DOM 元素并从中读取值。在第二个中,您只需循环一个普通数组

C)可以通过ajax加载或刷新数据。您只传输 JSON 对象,而不传输显示数据所需的所有 HTML 内容

D)性能要好得多,主要是因为上述几点。Javascript 在处理简单数组或(不太复杂的)JSON 对象方面比在从 DOM 树中过滤数据方面要好得多。

一般来说,这种解决方案的速度是第一种情况的两倍多。您还会发现——尽管不是很明显——第二种情况也更容易编码和维护!代码更容易阅读和理解,因为您清楚地将数据与 UI 元素分开......

性能比较

您可以在此 JSPerf 场景中比较两种解决方案:http: //jsperf.com/performance-on-data-storage

更进一步

对于第二种情况的实现,我通常使用这种方法:

  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 回答