【引自雕刻零碎的博客】一、性能优化的原则及方法论
树立原则:动态渲染进入一个Dom元素,首先需要保证动态渲染操作必须尽可能少对原有dom树的影响,影响重绘及重排。
确定方法论:必须寻找一个容器来缓存渲染期间生成的dom结构(操作必须尽可能少对原有dom树的影响),然后再进行一次渲染到目标element中。
二、生成期间DOM缓存的选择
三、DocumentFragment的优缺点
基本模式:
- var fragment = document.createDocumentFragment();
- fragment.appendChild(
- ... //生成Element的IIFE
- )
- //IIFE示例,根据配置创建元素
- var ConfigVar = {
- ELname:"div",
- id:"blablabla",
- name:"balblabla",
- class:"ClassName"
- }
- (function(Config){
- var el = document.createElement(Config.ELname);
- el.className = (Config.class || "");
- for (let AttrName in Config){
- if (AttrName == "class")continue;
- el.setAttribute(AttrName,Config[AttrName]);
- }
- return el;
- })(ConfigVar)
优点
1、脱离于文档流,操作不会对Dom树产生影响
2、在每一次生成临时Element时候就可以将该Element对象的引用保存下来,而不需要多次用选择器再次获取。
缺点
兼容性只是达到IE9+
http://caniuse.com/#search=DocumentFragment
四、createElement的优缺点
基本模式
- var el = document.createElement("ElementName");
- el.className = "";
- el.setAttribute("AttrName",AttrValue);
- el.setAttribute("AttrName",AttrValue);
- ...
- el.appendChild(
- ... //生成Element的IIFE,见上文
- );
优点
1、新创建的元素脱离于文档流,操作不会对Dom树产生影响
2、兼容性***
3、在每一次生成临时Element时候就可以将该Element对象的引用保存下来,而不需要多次用选择器再次获取。
缺点
每一次调用setAttribute方法都是一次次对Element进行修改,此处具有潜在的性能损耗。
五、DomString——临时Element+innerHTML+cloneNode的优缺点
基本模式
- var domString2Dom = (function(){
- if (window.HTMLTemplateElement){
- var container = document.createElement("template");
- return function(domString){
- container.innerHTML = domString;
- return container.content.firstChild.cloneNode(true)
- }
- }else{
- //对不支持的template 的浏览器还有兼容性方法没写,所以不支持tr,td等些元素inner进div中。
- var container = document.createElement("div");
- return function(domString){
- container.innerHTML = domString;
- return container.firstChild.cloneNode(true)
- }
- }
- })();
- var template = domString2Dom('');
- for (var index = 0; index < 80; index++) {
- template.appendChild(
- (function(){
- var el = domString2Dom("
M");- return el
- })()
- )
- }
优点
创建Dom之后不需要多次进行setAttribute
缺点
1、临时元素不能包裹一些特定的元素(不能在所有浏览器的所有 HTML 元素上设置 innerHTML 属性)
2、解析的过程进行了很多其余的操作。此处具有潜在的性能损耗。
3、插入的字符串***层Node只允许有一个元素
六、DomString——XML解析的优缺点
基本模式
- var XMLParser = function () {
- var $DOMParser = new DOMParser();
- return function (domString) {
- if (domString[0] == "<") {
- var doc = $DOMParser.parseFromString(domString, "application/xhtml+xml");
- return doc.firstChild;
- }
- else {
- return document.createTextNode(domString);
- }
- };
- }();
- var template = XMLParser('');
- for (var index = 0; index < 80; index++) {
- template.appendChild((function () {
- var el = XMLParser("
M");- return el;
- })());
- }
优点
DomString方法中通用性***的,虽然IE10+才支持DOMParser,但是IE9以下的有替代方法
缺点
1、解析的过程本身就具有潜在的性能损耗。
2、只能得到刚刚创建最外层元素的克隆。子元素的引用还需要用选择器。
3、插入的字符串***层Node只允许有一个元素
七、临时字符串的优缺点
基本模式:
- var template = document.createElement("div");
- template.innerHTML = `
` //需要增加的一大段Element- Test TextNode
- ${(function(){
- var temp = new Array(8);
- for (var index = 0; index < 80; index++) {
- temp[index]="
M"- }
- return temp.join()
- }())}
优点
1、通用性***,不需要逐步创建一大堆无用的Element对象引用
2、运用es6模板字符串编码优雅,不需要字符串用加号进行链接
缺点
1、如果是直接给出配置Config进行渲染需要进行字符串的生成
2、只能得到刚刚创建最外层元素的引用。子元素的引用还需要用选择器。
八、Template元素
由于HTML5中新增了template元素
其特点就是有一个content属性是HTMLDocumentFragment对象,所以可以包容任何元素
基本范式是:
- var template = document.createElement("template");
- template.innerHTML = `
` //需要增加的一大段Element- Test TextNode
- ${(function(){
- var temp = new Array(8);
- for (var index = 0; index < 80; index++) {
- temp[index]="
M"- }
- return temp.join()
- }())}
- // template.content 是HTMLDocumentFragment
优点
比div要好很多,作为临时元素容器的包容性更强
缺点
兼容性不好:http://caniuse.com/#search=HTML%20templates 在不支持的浏览器中表示为HTMLUnknownElement
九、各种方法的效率对比
测试代码:(由于笔者不太熟悉各种浏览器性能的BUG,这里的代码如果有不足请指正),代码由typescript进行编写,也可以用babel进行编译。
- /**
- * @param Count:渲染DOM结构的次数
- */
- var DateCount = {
- TimeList : {},
- time:function(Str){
- console.time(Str);
- },
- timeEnd:function(Str){
- console.timeEnd(Str);
- }
- };
- //==================工具函数======================
- var domString2Dom = (function () {
- var container;
- if (window.HTMLTemplateElement) {
- container = document.createElement("template");
- return function (domString) {
- container.innerHTML = domString;
- return container.content.firstChild.cloneNode(true);
- };
- }
- else {
- //对不支持的template 的浏览器还有兼容性方法没写,所以不支持tr,td等些元素inner进div中。
- container = document.createElement("div");
- return function (domString) {
- container.innerHTML = domString;
- return container.firstChild.cloneNode(true);
- };
- }
- })();
- var XMLParser = (function () {
- var $DOMParser;
- if (window.DOMParser) {
- $DOMParser = new DOMParser();
- return function (domString) {
- if (domString[0] == "<") {
- var doc = $DOMParser.parseFromString(domString, "application/xhtml+xml");
- return doc.firstChild;
- }
- else {
- return document.createTextNode(domString);
- }
- };
- }else{
- $DOMParser = new ActiveXObject("Microsoft.XMLDOM");
- return function (domString) {
- if (domString[0] == "<") {
- $DOMParser.async = false;
- $DOMParser.loadXML(domString);
- return $DOMParser
- }
- else {
- return document.createTextNode(domString);
- }
- }
- }
- })();
- //===============================================
- var Test = function(Count){
- //保留这种写法,能够在移动端平台中不依靠控制台进行效率测试
- // var DateCount = {
- // TimeList : {},
- // time:function(Str){
- // this.TimeList[Str] = Date.now();
- // },
- // timeEnd:function(Str){
- // alert(Str+(Date.now() - this.TimeList[Str]));
- // }
- // }
- //基准测试1:
- DateCount.time("无临时div + 不需要字符串拼接 + innerHTML:")
- for (let index = 0; index < Count; index++) {
- (function(){
- var template = document.createElement("div");
- template.className = "TestClass";
- template.setAttribute("Arg","TestArg")
- template.innerHTML = ` Test TextNode
MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM MMMMMMMMMM- ` //需要增加的一大段Element,共100个子级div
- return template
- }())
- }
- DateCount.timeEnd("无临时div + 不需要字符串拼接 + innerHTML:")
- //基准测试2:
- DateCount.time("createElement+appendChild写法:")
- for (let index = 0; index < Count; index++) {
- (function(){
- var template = document.createElement("div");
- template.className = "TestClass";
- template.setAttribute("Arg","TestArg")
- template.appendChild(document.createTextNode('Test TextNode'));
- for (let index = 0; index < 100; index++) {
- let element = document.createElement("div");
- element.setAttribute("child","true");
- element.appendChild(document.createTextNode("M"))
- template.appendChild(element)
- }
- return template
- }())
- }
- DateCount.timeEnd("createElement+appendChild写法:")
- //DocumentFragment
- DateCount.time("DocumentFragment+ createElement+appendChild 写法:")
- for (let index = 0; index < Count; index++) {
- (function(){
- var fragment = document.createDocumentFragment();
- fragment.appendChild(function(){
- var template = document.createElement("div");
- template.className = "TestClass";
- template.setAttribute("Arg","TestArg")
- template.appendChild(document.createTextNode('Test TextNode'));
- for (let index = 0; index < 100; index++) {
- let element = document.createElement("div");
- element.setAttribute("child","true");
- template.appendChild(element)
- }
- return template;
- }());
- return fragment
- }())
- }
- DateCount.timeEnd("DocumentFragment+ createElement+appendChild 写法:")
- //DomString——临时Element+innerHTML+cloneNode
- // DateCount.time("DomString——临时Element+innerHTML+cloneNode:")
- // for (let index = 0; index < Count; index++) {
- // (function(){
- // var template = domString2Dom('');
- // for (let index = 0; index < 100; index++) {
- // template.appendChild(
- // (function(){
- // var el = domString2Dom("
M");- // return el
- // })()
- // )
- // }
- // return template;
- // }())
- // }
- // DateCount.timeEnd("DomString——临时Element+innerHTML+cloneNode:")
- //DomString——XML解析
- // DateCount.time("DomString——XML解析:")
- // for (let index = 0; index < Count; index++) {
- // (function(){
- // var template = XMLParser('');
- // for (let index = 0; index < 100; index++) {
- // template.appendChild((function () {
- // var el = XMLParser("
M");- // return el;
- // })());
- // }
- // }())
- // }
- // DateCount.timeEnd("DomString——XML解析:")
- //临时div + 临时字符串拼接:
- DateCount.time("临时div + 字符串拼接:")
- for (let index = 0; index < Count; index++) {
- (function(){
- let template = document.createElement("div");
- template.innerHTML = `
` //需要增加的一大段Element- Test TextNode
- ${(function(){
- let temp = "";
- for (let index = 0; index < 100; index++) {
- temp+="
M"- }
- return temp
- }())}
- return template.firstChild;
- }())
- }
- DateCount.timeEnd("临时div + 字符串拼接:")
- //临时template + 临时字符串拼接:
- DateCount.time("临时template + 字符串拼接:")
- for (let index = 0; index < Count; index++) {
- (function(){
- var template = document.createElement("template");
- template.innerHTML = `
` //需要增加的一大段Element- Test TextNode
- ${(function(){
- let temp = "";
- for (let index = 0; index < 100; index++) {
- temp+="
M"- }
- return temp
- }())}
- return template.content;
- }())
- }
- DateCount.timeEnd("临时template + 字符串拼接:")
- //临时template + createElement+appendChild 写法
- DateCount.time("template + createElement+appendChild 写法:")
- for (let index = 0; index < Count; index++) {
- (function(){
- var template = document.createElement("template");
- template.appendChild(function(){
- var template = document.createElement("div");
- template.className = "TestClass";
- template.setAttribute("Arg","TestArg")
- template.appendChild(document.createTextNode('Test TextNode'));
- for (let index = 0; index < 100; index++) {
- let element = document.createElement("div");
- element.setAttribute("child","true");
- template.appendChild(element)
- }
- retur
标题名称:各种动态渲染Element方式的性能探究
当前链接:http://www.csdahua.cn/qtweb/news22/474772.html网站建设、网络推广公司-快上网,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 快上网