jQuery 使用jQuery动态生成html的正确方法

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/7686770/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 00:10:22  来源:igfitidea点击:

Proper way to generate html dynamically with jQuery

jqueryhtmlperformancedom

提问by Przemek

I found some different and conflicting answers on this topic.

我在这个主题上发现了一些不同且相互矛盾的答案。

I am building an application which works mostly with html dynamically generated by jQuery, based on results acquired from underlying API in form of JSON data.

我正在构建一个应用程序,它主要使用 jQuery 动态生成的 html,基于从底层 API 以 JSON 数据的形式获取的结果。

I was told by some of my collegues (personally), that the best way would be to do something like this:

我的一些同事(个人)告诉我,最好的方法是做这样的事情:

var ul = $("<ul>").addClass("some-ul");
$.each(results, function(index) {
  ul.append($("<li>").html(this).attr("id", index));
});
$("body").append($("<div>").attr("id", "div-id").addClass("some-div").append(ul));

etc. The reason I was told it was that "updates the DOM directly instead of parsing html to achieve it".

等等。我被告知的原因是“直接更新 DOM 而不是解析 html 来实现它”。

However, I see lots of code like this (same example):

但是,我看到很多这样的代码(同一个例子):

var toAppend = '<div class="some-div" id="div-id"><ul>';
$.each(results, function(index) {
  toAppend += '<li id="' + index + '">' + this + '</li>';
});
toAppend += '</ul></div>'

Which I personally consider as not as elegant - but is it better? I googled the issue for a couple of minutes and found this article. Basically, it is about increasing performance drastically by using string concatenation - my "second way".

我个人认为它不那么优雅 - 但它更好吗?我用谷歌搜索了这个问题几分钟,找到了这篇文章。基本上,它是关于通过使用字符串连接来大幅提高性能——我的“第二种方式”。

The main issue of this article is that it has been released in 2009 and discussed jQuery version is 1.3. Today, the current release is version 1.6.4 which can behave quite differently. And this is the issue of most articles on the subject I have already found and I'm also somehow suspicious about their credibility.

本文的主要问题是它已于 2009 年发布,并讨论了 jQuery 版本为 1.3。今天,当前版本是 1.6.4 版,它的行为可能完全不同。这是我已经找到的大多数关于该主题的文章的问题,我也怀疑它们的可信度。

That's why I have decided to post the question here and ask - which method of generating DOM is actually the proper one, based on performance?

这就是为什么我决定在这里发布问题并询问 - 基于性能,哪种生成 DOM 的方法实际上是正确的?

IMPORTANT EDIT:

重要编辑:

I have written a little benchmark to test which approach is better considering performance.

我写了一个小基准来测试哪种方法更好地考虑性能。

jsFiddle- concatenation version

jsFiddle- 连接版本

jsFiddle- array join version

jsFiddle- 数组连接版本

Code:

代码:

var text = "lorem ipsum";
var strings = $("#strings");
var objects = $("#objects");
var results = $("#results");

// string concatenation
var start = new Date().getTime();
var toAppend = ['<div class="div-class" id="div-id1"><ul class="ul-class" id="ul-id1">'];
for (var i = 1; i <= 20000; i++) {
    toAppend[i] = '<li class="li-class" id="li-id1-' + i + '">' + text + '</li>';
}
toAppend[i++] = '</ul></div>';
results.append(toAppend.join(""));
strings.html(new Date().getTime() - start);

// jquery objects
var start = new Date().getTime();
var ul = $("<ul>").attr("id", "ul-id2").addClass("ul-class");
for (var i = 0; i < 20000; i++) {
    ul.append($("<li>").attr("id", "li-id2-" + i).addClass("li-class"));
}
results.append($("<div>").attr("id", "div-id2").addClass("div-class").append(ul));
objects.html(new Date().getTime() - start);

It seems that operating on strings is faster (in Firefox 7 about 7 times) than using jQuery objects and methods. But I can be wrong, especially if there are any mistakes or performance-decreasing bugs in this "benchmark's" code. Feel free to make any changes.

似乎操作字符串比使用 jQuery 对象和方法更快(在 Firefox 7 中大约是 7 倍)。但我可能是错的,特别是如果这个“基准”代码中存在任何错误或降低性能的错误。随意进行任何更改。

Note: I used Array joinbecause of the article mentioned earlier instead of actual concatenation.

注意:我使用 Arrayjoin是因为前面提到的文章而不是实际的串联。

EDIT: Based on suggestion by @hradac, I used actual string concatenation in the benchmark and it did in fact improve the times.

编辑:根据@hradac 的建议,我在基准测试中使用了实际的字符串连接,它确实提高了时间。

采纳答案by John Munsch

First of all, this kind of micro-benchmarking almost never tells you what you want to really know. Second of all, your benchmarks are varied and not equivalent. For example, your first example generates lines that look like this:

首先,这种微基准测试几乎不会告诉你你真正想知道什么。其次,你的基准是多种多样的,而不是等同的。例如,您的第一个示例生成如下所示的行:

<li class="li-class" id="li-id1-493">lorem ipsum</li>

and your second lines like this:

你的第二行是这样的:

<li id="li-id2-0" class="li-class"></li>

Notice the different element order and the lack of "lorem ipsum" text. Nor is there any attempt to clean out the results div between tests to avoid performance issues as a result of the first 20K results already being there.

注意不同的元素顺序和缺少“lorem ipsum”文本。也没有任何尝试清除测试之间的结果 div 以避免由于前 20K 结果已经存在而导致的性能问题。

But beyond these issues is the question, "Is performance on this really disrupting the client side user experience?" Seriously? You're rendering such a quantity of text this way that you're seeing noticeable differences between the alternative methods rendering the text?

但除了这些问题之外,还有一个问题,“这方面的性能真的会破坏客户端的用户体验吗?” 严重地?您以这种方式渲染了如此多的文本,以至于您发现渲染文本的替代方法之间存在明显差异?

I'll harken back to what others have said, use a templating engine. The fastest ones are quite quick indeed and even have pre-compilation options to allow you to re-render the same template and get quick results. So don't believe me. Instead, believe a demonstration. Here's my jsFiddle to demonstrate the performance of the new JsRender library that is supposed to replace the jQuery Template engine...

我会回到其他人所说的,使用模板引擎。最快的确实很快,甚至有预编译选项,允许您重新渲染相同的模板并快速获得结果。所以不要相信我。相反,相信示范。这是我的 jsFiddle 来演示应该替换 jQuery 模板引擎的新 JsRender 库的性能......

http://jsfiddle.net/LZLWM/10/

http://jsfiddle.net/LZLWM/10/

Note: It can take several seconds for JsRender to load into the Fiddle. It's because I'm pulling it straight out of GitHub and that's not something that GitHub is particularly good at. I don't recommend that in actual practice. It doesn't change the timings though and it's necessary until jsFiddle starts incorporating templating engines as options.

注意:JsRender 可能需要几秒钟才能加载到 Fiddle 中。这是因为我是直接从 GitHub 中提取出来的,而这并不是 GitHub 特别擅长的。我不建议在实际操作中这样做。虽然它不会改变时间,但在 jsFiddle 开始将模板引擎作为选项合并之前,这是必要的。

Notice that the second example, much closer to a real-world example generates 20,000 lines using JSON as its starting point in time approximately the same as your fastest test (< 50ms difference on my machine). Note also that both the code and the template are much clearer and easier to work with than any mess of appends and string concatenation is ever going to be. How many iterations am I going to need to get my template right vs. what you're doing?

请注意,第二个示例更接近真实世界的示例,使用 JSON 作为其起始时间点生成 20,000 行,与您的最快测试大致相同(我的机器上的差异小于 50 毫秒)。还要注意,代码和模板都比任何混乱的追加和字符串连接都更清晰、更容易使用。我需要多少次迭代才能使我的模板正确与您在做什么?

Use something simple and stop wasting time on this level of micro optimization when it's probably not even necessary. Instead use templates like this (or any of several other good templating engines) and make sure that you've got expires headers turned on, you're using a CDN, you've got gzip compression turned on on your server, etc. All the stuff that YSlow is telling you to do, because that will completely swamp the effects of what you're looking at here.

使用一些简单的方法,并在可能根本不需要时停止在这种级别的微优化上浪费时间。而是使用这样的模板(或其他几个好的模板引擎中的任何一个),并确保您已打开过期标头,您正在使用 CDN,您已在您的服务器上打开 gzip 压缩,等等。所有YSlow 告诉你要做的事情,因为那会完全淹没你在这里看到的东西的影响。

回答by John Strickler

回答by RedFilter

Generally, I think readability trumps performance unless you are actually having issues. I would opt for the second approach as it is easily recognizable as a standard HTML snippet, and I think less prone to errors.

一般来说,我认为可读性胜过性能,除非你真的有问题。我会选择第二种方法,因为它很容易被识别为标准的 HTML 片段,而且我认为不太容易出错。

With the first method, I have to parse a lot of code in my minhd just to imagine what the final string will look like (and thus where it might need modifications).

使用第一种方法时,我必须在 minhd 中解析大量代码才能想象最终字符串的样子(以及可能需要修改的地方)。

回答by swatkins

Your first approach is better. The idea is not to touch the DOM until you have to. In both examples, you create the UL in memory and then at the end you attach it to the DOM with body.append().

你的第一种方法更好。这个想法不是在你不得不接触 DOM 之前。在这两个示例中,您都在内存中创建了 UL,然后最后使用body.append().

However, the preferred way to build a tree is in your first example. The string concatenation is a bit slower (of course, we're talking milliseconds). However, if you have to do this many times per page, that could become significant.

但是,构建树的首选方法是在您的第一个示例中。字符串连接有点慢(当然,我们说的是毫秒)。但是,如果您必须在每页上多次执行此操作,这可能会变得很重要。

I'd clean up your code a bit, but only for readability:

我会稍微清理一下你的代码,但只是为了可读性:

var div = $("<div>").attr("id", "div-id").addClass("some-div");
var ul = $("<ul>").addClass("some-ul");
$.each(results, function(index) {
    var li = $("<li>").html(this).attr("id", index);
    ul.append(li);
});
div.append(ul);

// you haven't touched the DOM yet, everything thus far has been in memory

$("body").append(div); // this is the only time you touch the DOM

回答by Kevin B

Basically, the first method uses multiple method calls to .innerHTML to create the result while the second method only uses one. This is the primary area that causes the difference in the amount of time that it takes to execute.

基本上,第一种方法使用对 .innerHTML 的多个方法调用来创建结果,而第二种方法只使用一个。这是导致执行时间差异的主要区域。

I would suggest a 3rd method using an array if the strings get extremely large.

如果字符串变得非常大,我会建议使用数组的第三种方法。

var toAppend = ['<div class="some-div" id="div-id"><ul>'];
$.each(results, function(index) {
  toAppend.push('<li id="' + index + '">' + this + '</li>');
});
toAppend.push('</ul></div>');
$(target).append(toAppend.join(""));

I generally use the array method only to be consistant.

我通常使用数组方法只是为了保持一致。

Edit: hradac is right, the concatenate method is faster now.

编辑:hradac 是对的,连接方法现在更快了。