本篇內(nèi)容介紹了“各種動態(tài)渲染Element方式的性能分析”的有關(guān)知識,在實際案例的操作過程中,不少人都會遇到這樣的困境,接下來就讓小編帶領(lǐng)大家學(xué)習(xí)一下如何處理這些情況吧!希望大家仔細閱讀,能夠?qū)W有所成!
創(chuàng)新互聯(lián)是一家專注于成都做網(wǎng)站、網(wǎng)站設(shè)計與策劃設(shè)計,廣靈網(wǎng)站建設(shè)哪家好?創(chuàng)新互聯(lián)做網(wǎng)站,專注于網(wǎng)站建設(shè)十載,網(wǎng)設(shè)計領(lǐng)域的專業(yè)建站公司;建站業(yè)務(wù)涵蓋:廣靈等地區(qū)。廣靈做網(wǎng)站價格咨詢:028-86922220
一、性能優(yōu)化的原則及方法論
樹立原則:動態(tài)渲染進入一個Dom元素,首先需要保證動態(tài)渲染操作必須盡可能少對原有dom樹的影響,影響重繪及重排。
確定方法論:必須尋找一個容器來緩存渲染期間生成的dom結(jié)構(gòu)(操作必須盡可能少對原有dom樹的影響),然后再進行一次渲染到目標element中。
二、生成期間DOM緩存的選擇
DocumentFragment(文檔碎片對象,選擇原因:脫離于文檔流)
臨時Element(選擇原因:新element脫離于文檔流)
臨時Element+innerHTML+cloneNode返回最外層element元素對象,再進行插入appendChild,必要時還需要選擇器方法講某一個Element對象提取出來
XML字符串通過解析生成Element對象(注意,不是HTMLxxxElement對象,是Element對象),然后將該對象appendChild進去
createElement,再一步步進行渲染
通過描述Dom的String(下稱:DomString),轉(zhuǎn)化為Dom對象
臨時字符串(選擇原因:借助innerHTML渲染,一次渲染)
三、DocumentFragment的優(yōu)缺點
基本模式:
var fragment = document.createDocumentFragment(); fragment.appendChild( ... //生成Element的IIFE )
//IIFE示例,根據(jù)配置創(chuàng)建元素 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)
優(yōu)點
1、脫離于文檔流,操作不會對Dom樹產(chǎn)生影響
2、在每一次生成臨時Element時候就可以將該Element對象的引用保存下來,而不需要多次用選擇器再次獲取。
缺點
兼容性只是達到IE9+
四、createElement的優(yōu)缺點
基本模式
var el = document.createElement("ElementName"); el.className = ""; el.setAttribute("AttrName",AttrValue); el.setAttribute("AttrName",AttrValue); ... el.appendChild( ... //生成Element的IIFE,見上文 );
優(yōu)點
1、新創(chuàng)建的元素脫離于文檔流,操作不會對Dom樹產(chǎn)生影響
2、兼容性***
3、在每一次生成臨時Element時候就可以將該Element對象的引用保存下來,而不需要多次用選擇器再次獲取。
缺點
每一次調(diào)用setAttribute方法都是一次次對Element進行修改,此處具有潛在的性能損耗。
五、DomString——臨時Element+innerHTML+cloneNode的優(yōu)缺點
基本模式
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 })() ) }
優(yōu)點
創(chuàng)建Dom之后不需要多次進行setAttribute
缺點
1、臨時元素不能包裹一些特定的元素(不能在所有瀏覽器的所有 HTML 元素上設(shè)置 innerHTML 屬性)
2、解析的過程進行了很多其余的操作。此處具有潛在的性能損耗。
3、插入的字符串***層Node只允許有一個元素
六、DomString——XML解析的優(yōu)缺點
基本模式
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; })()); }
優(yōu)點
DomString方法中通用性***的,雖然IE10+才支持DOMParser,但是IE9以下的有替代方法
缺點
1、解析的過程本身就具有潛在的性能損耗。
2、只能得到剛剛創(chuàng)建最外層元素的克隆。子元素的引用還需要用選擇器。
3、插入的字符串***層Node只允許有一個元素
七、臨時字符串的優(yōu)缺點
基本模式:
var template = document.createElement("div"); template.innerHTML = `Test TextNode ${(function(){ var temp = new Array(8); for (var index = 0; index < 80; index++) { temp[index]="` //需要增加的一大段ElementM" } return temp.join() }())}
優(yōu)點
1、通用性***,不需要逐步創(chuàng)建一大堆無用的Element對象引用
2、運用es6模板字符串編碼優(yōu)雅,不需要字符串用加號進行鏈接
缺點
1、如果是直接給出配置Config進行渲染需要進行字符串的生成
2、只能得到剛剛創(chuàng)建最外層元素的引用。子元素的引用還需要用選擇器。
八、Template元素
由于HTML5中新增了template元素
其特點就是有一個content屬性是HTMLDocumentFragment對象,所以可以包容任何元素
基本范式是:
var template = document.createElement("template"); template.innerHTML = `Test TextNode ${(function(){ var temp = new Array(8); for (var index = 0; index < 80; index++) { temp[index]="` //需要增加的一大段Element // template.content 是HTMLDocumentFragmentM" } return temp.join() }())}
優(yōu)點
比div要好很多,作為臨時元素容器的包容性更強
缺點
在不支持的瀏覽器中表示為HTMLUnknownElement
九、各種方法的效率對比
測試代碼:(由于筆者不太熟悉各種瀏覽器性能的BUG,這里的代碼如果有不足請指正),代碼由typescript進行編寫,也可以用babel進行編譯。
/** * @param Count:渲染DOM結(jié)構(gòu)的次數(shù) */ var DateCount = { TimeList : {}, time:function(Str){ console.time(Str); }, timeEnd:function(Str){ console.timeEnd(Str); } }; //==================工具函數(shù)====================== 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 TextNodeMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM` //需要增加的一大段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 = `Test TextNode ${(function(){ let temp = ""; for (let index = 0; index < 100; index++) { temp+="` //需要增加的一大段Element 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 = `M" } return temp }())}Test TextNode ${(function(){ let temp = ""; for (let index = 0; index < 100; index++) { temp+="` //需要增加的一大段Element 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) } return template; }()); return template.content }()) } DateCount.timeEnd("template + createElement+appendChild 寫法:") }; for (var key of [1,10,100,1000]) { console.log("Start"+key); Test(key); }M" } return temp }())}
“各種動態(tài)渲染Element方式的性能分析”的內(nèi)容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業(yè)相關(guān)的知識可以關(guān)注創(chuàng)新互聯(lián)網(wǎng)站,小編將為大家輸出更多高質(zhì)量的實用文章!