摘要:第三種將原始元素拷貝到一個(gè)脫離文檔的節(jié)點(diǎn)中,修改副本,完成后在提貨原始元素以上脫離文檔流修改的方法推薦第二種方法。對(duì)于用展開(kāi)折疊的效果,我們使用絕對(duì)定位,將其脫離文檔流,會(huì)是重繪更少些。
本文的一些注意的是我以前看書籍總結(jié)的,我們一般人寫項(xiàng)目時(shí),對(duì)我們的影響并不是很大,有時(shí)完全可以忽略,但是我們知道這些總不是什么壞處。
js這個(gè)大眾語(yǔ)言我想,很多人多知道,它入門和簡(jiǎn)單,可是想要深入了解還是要有一定的水平、 的,同樣的效果雖然都可以寫出來(lái),但還是性能和可維護(hù)性卻有很大差別。下來(lái)我們就來(lái)總結(jié)一下書寫高質(zhì)量js代碼的一些注意點(diǎn)。
代碼維護(hù)是高成本的,如果我們?cè)陂_(kāi)發(fā)代碼時(shí),不注重代碼的規(guī)范,可讀性和可維護(hù)性,那么將來(lái)帶給我們的將是更大的開(kāi)支。如果說(shuō)你是給公司干活,自己寫完就不用管了,這樣的思想很危險(xiǎn)。不但對(duì)他人讀取你代碼時(shí)帶來(lái)困擾,同時(shí)也是限制自己發(fā)展的一個(gè)障礙。代碼終究是要給人去閱讀的。我們整個(gè)團(tuán)隊(duì)在書寫代碼時(shí)應(yīng)該勁量做到:
可讀的
一致的
可預(yù)測(cè)的
看上去就像是同一個(gè)人寫的
已記錄
執(zhí)行與加載管理瀏覽器中的腳本 JavaScript 代碼是個(gè)棘手的問(wèn)題,因?yàn)榇a執(zhí)行過(guò)程會(huì)阻塞瀏覽器的其他進(jìn)程,比如用戶界面繪制,每次遇到標(biāo)簽,頁(yè)面都必須停下來(lái)等待代碼下載(如果是外鏈文件)并執(zhí)行,然后繼續(xù)處理其他部分,盡管如此,還是有幾種方法能減少javascript 對(duì)性能的影響。
閉合標(biāo)簽之前,將所有的標(biāo)簽放到頁(yè)面底部,這確保在腳本執(zhí)行前頁(yè)面已加載完成了渲染。
合并腳本,頁(yè)面中的 標(biāo)簽越少,加載也就也快,響應(yīng)也更迅速。無(wú)論外鏈文件還是內(nèi)嵌腳本都是如此
有多種無(wú)阻塞下載JavaScript方法:
使用標(biāo)簽的defer屬性(H5提供一個(gè)新屬性async)
defer和async的相同點(diǎn)是采用并行下載,在下載過(guò)程中不會(huì)產(chǎn)生阻塞。區(qū)別在于執(zhí)行時(shí)機(jī),async是加載完成后自動(dòng)執(zhí)行,而defer需要等待頁(yè)面完成后執(zhí)行。
使用動(dòng)態(tài)創(chuàng)建元素來(lái)下載并執(zhí)行代碼
使用動(dòng)態(tài)創(chuàng)建元素不會(huì)阻塞頁(yè)面的其他進(jìn)程,這樣我們可以將動(dòng)態(tài)創(chuàng)建的放到頁(yè)面的 區(qū)域。
function(url){ var script = document.creatElement("script"); script.type = "text/javascript"; script.src = url; document.getElementsByTagName("head")[0].appendChild(script); }
我們什么時(shí)候知道腳本已經(jīng)加載完成呢?Firefox,Opera,Chrome和safari3為我們提供了一個(gè)onload事件來(lái)監(jiān)聽(tīng),而IE 為我們提供了onreadystatechange 事件并根據(jù)readyState屬性來(lái)進(jìn)行判斷。
通過(guò)上面的方法,我們可以極大提高那些需要使用大量的JavaScript 的 web應(yīng)用的實(shí)際性能
變量處理我們都知道,JavaScript通過(guò)函數(shù)管理作用域。在函數(shù)內(nèi)部聲明的變量只在這個(gè)函數(shù)內(nèi)部,函數(shù)外面不可用。另一方面,全局變量就是在任何函數(shù)外面聲明的或是未聲明直接簡(jiǎn)單使用的。我們應(yīng)該盡量的減少全局變量,這樣避免全局變量過(guò)多而造成變量命名沖突,同時(shí)又占用內(nèi)存。
聲明變量是我們盡量用var去聲明
function fun(){ a = 1; // 這樣是不推薦的,因?yàn)閍是隱式的全局變量 var b = 2; // 這樣是推薦的 var c = d = 5 // 這樣也是不推薦的,因?yàn)閐是隱式的全局變量 }
減少全局變量我們還可以使用立即執(zhí)行函數(shù),下來(lái)我們也會(huì)有章節(jié)去詳細(xì)的講解
(function(){ var a = 3; var b = 4; })()
另外我們應(yīng)該知道變量提升原則,這個(gè)在后面的章節(jié)中我們還會(huì)詳細(xì)的講解我們?cè)趯懸恍┳兞繒r(shí),可以這樣去寫。
function(){ var a, b, c; a = 1; b = 2; c = 3; }
我們把常用的變量寫到最上面,可以進(jìn)行注釋,這樣更有利于維護(hù)我們的代碼,同時(shí)防止變量在定義之前使用的邏輯錯(cuò)誤。
DOM操作的注意點(diǎn)腳本進(jìn)行DOM的操作的代價(jià)是很昂貴的。它是富Web應(yīng)用中最常見(jiàn)的性能瓶頸。瀏覽器中通常會(huì)把DOM 和 JavaScript(ECMAScript) 獨(dú)立實(shí)現(xiàn)。我們每一次用js去操作DOM都會(huì)產(chǎn)生性能消耗,所以我們盡可能小的去處理DOM,這也是現(xiàn)在MVVM和MVC框架流行的一部分原因。我們?cè)谔幚鞤OM時(shí)盡可能這樣做。
1.最小化DOM訪問(wèn)次數(shù),盡可能在JavaScript端處理
var ul = document.getElementById("ul"); var a = ""; for(var i=0;i<10;i++){ a += "
"; } ul.innerHTML = a;
將要添加的標(biāo)簽存儲(chǔ)在變量a中,一次性加入ul中,這樣只訪問(wèn)一次dom,降低了性能消耗。
2.如果需要多次訪問(wèn)某個(gè)DOM節(jié)點(diǎn),請(qǐng)使用局部變量存儲(chǔ)它的引用
var doc = document; // 存儲(chǔ)document doc.getElementById("div");
3.小心處理HTML集合,因?yàn)樗鼘?shí)時(shí)連系著底層文檔,把集合的長(zhǎng)度緩存到一個(gè)變量中,并在迭代中使用它。如果需要經(jīng)常操作集合,建議把它拷貝到一個(gè)數(shù)組中。
var divList = document.getElementsByTagName("div"); for(var i = 0,len = divList.length; i < len; i++){ }
這里我們將divList的長(zhǎng)度去存儲(chǔ)在變量 len中,而不像下面這樣每次循環(huán)都要讀取一遍長(zhǎng)度。
// 避免使用的例子 var divList = document.getElementsByTagName("div"); for(var i = 0; i < divList.length; i++){ }
4.如果可能的話,使用速度更快的API,比如querySelectorAll() 和 firstElementChild
5.要留意重繪和重排;批量修改樣式時(shí),"離線"操作DOM樹(shù),使用緩存、并減少訪問(wèn)布局信息的次數(shù)
瀏覽器下載完頁(yè)面中的所有組件之后會(huì)解析并生成兩個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu)
DOM樹(shù): 表示頁(yè)面結(jié)構(gòu)
渲染樹(shù): 表示DOM節(jié)點(diǎn)如何顯示
當(dāng)DOM的變化影響了元素的幾何屬性時(shí)(寬高)—— 比如改變框?qū)挾然蚪o段落增加文字,導(dǎo)致行數(shù)增加,瀏覽器需要重新計(jì)算元素的幾何屬性,同樣其他元素的幾何屬性和位置也會(huì)因此受到影響,瀏覽器會(huì)是渲染樹(shù)中受到影響的部分失效,并重新構(gòu)造渲染樹(shù)。這一過(guò)程稱為 “重排(reflow)”。完成重排后,瀏覽器會(huì)重新繪制影響的部分到屏幕中,該過(guò)程稱為 “重繪”。
那么我們?cè)撛趺礈p少重排和重繪
樣式統(tǒng)一處理
我們?cè)诟淖円粋€(gè)元素樣式時(shí),可以統(tǒng)一處理
//這種寫法不推薦 var el = document.getElementById("div"); el.style.width = "100px"; el.style.height = "100px"; el.style.padding = "10px"; //這種寫法推薦 var el = document.getElementById("div"); el.style.cssText = "width:100px;height:100px;padding:5px;";
下邊的方法很明顯只進(jìn)行了一次重排,而上邊的重排了三次。使用cssText時(shí)會(huì)覆蓋前邊的style樣式,我們可以這樣做
el.style.cssText += "width:100px;height:100px;padding:5px;";
另外我們還可以將改變的樣式寫在css樣式表中,通過(guò)修改class來(lái)改變其樣式。
var el = document.getElementById("div"); el.className = "active";
脫離文檔流修改DOM
脫離文檔修改DOM的步驟就是
使元素脫離文檔流
對(duì)其應(yīng)用多重改變
把元素帶回文檔中
這里我有三種方法:
(1) 第一種:隱藏元素,應(yīng)用修改,重新顯示
var el = document.getElementById("div"); el.style.display = "none"; el.style.width = "100px"; el.style.height = "100px"; el.style.padding = "10px"; el.style.display = "block";
(2) 第二種:使用文檔片段在當(dāng)前DOM之外構(gòu)建一個(gè)子樹(shù),在把它拷貝回文檔
var el = document.getElementById("ul"); var fragment = document.createDocumentFragment(); for(var i = 0; i < 50000; i++){ fragment.appendChild(document.createElement("li")); } el.appenChild(fragment);
推薦使用這種方式。
(3) 第三種:將原始元素拷貝到一個(gè)脫離文檔的節(jié)點(diǎn)中,修改副本,完成后在提貨原始元素
var el = document.getElementById("div"); var cloneDiv = el.choleNode(true); cloneDiv.appendChild = li; el.parentNode.replaceChild(clone,el);
以上脫離文檔流修改DOM的方法推薦第二種方法。
減少渲染變化的排隊(duì)與刷新
由于每次重排都會(huì)產(chǎn)生計(jì)算消耗,大多數(shù)瀏覽器通過(guò)列隊(duì)化修改并批量執(zhí)行來(lái)優(yōu)化重排過(guò)程。而我們不知不覺(jué)中就使用了一些強(qiáng)制刷新隊(duì)列并要求計(jì)劃任務(wù)立刻執(zhí)行的方法:
1. offsetTop、offsetLeft、offsetWidth、offsetHeight 2. scrollTop、scrollLeft、scrollWidth、scrollHeight 3. clientTop、clientLeft、clientWidht、clientHeight 4. getComputedStyle() // currentStyle IE中
我們?cè)谑褂蒙厦娣椒〞r(shí)要注意,瀏覽器為了返回最新值,會(huì)刷新隊(duì)列應(yīng)用所用變更,我們應(yīng)該減少他們的使用,如果使用他們我們最好緩存布局信息
例如我們將滾輪滾動(dòng)到頁(yè)面頂部:
var scroll = document.body.scrollTop; // 這里直接緩存scrollTop var set = setInterval(function(){ scroll--; // 這里不使用window.scrollTop-- document.body.scrollTop = scroll; if(scroll < 0) { clearInterval(set); } },100)
6.動(dòng)畫中使用絕對(duì)定位。
對(duì)于用展開(kāi)/折疊的效果,我們使用絕對(duì)定位,將其脫離文檔流,會(huì)是重繪更少些。
7.使用事件委托來(lái)減少事件處理器的數(shù)量。
如果你還不知道事件委托事什么,請(qǐng)?jiān)L問(wèn):
http://blog.csdn.net/webxiaoma/article/details/53501616
這里我們討論的是循環(huán)和判斷,我們直接寫推薦的書寫方法
1.循環(huán)體
循環(huán)包括 for循環(huán)、while循環(huán)、do-while循環(huán)、for-in循環(huán)。
其中for-in循環(huán)的性能明顯比其他性能差些,另外ES6對(duì)于屬性循環(huán)有出了for-of循環(huán),比起for-in循環(huán)性能要好一些。
我們前面也說(shuō)了,循環(huán)時(shí),我們最好存儲(chǔ)判斷的長(zhǎng)度,另外遞減循環(huán)要比遞加循環(huán)速度相當(dāng)要快。
2.判斷
判斷有:if 和 switch;
當(dāng)我們做判斷時(shí),最好是吧最有可能出現(xiàn)的放到前面,另外if-else-if很多的話,推薦使用switch去判斷,這樣更有利于減少性能的消耗。有時(shí)候我們選擇嵌套if也不使用很多if-else-if連用的方法如下:
// 推薦 if(){ if(){ if(){ } } } // 盡量少用 if(){ } else if(){ } else if(){ } else if(){ } else if(){ } else if(){ }對(duì)象和作用域
對(duì)象的注意點(diǎn)是:
1.盡量不擴(kuò)展內(nèi)置原型(如給Object.prototype添加自己的方法),除非你確定不會(huì)對(duì)你的團(tuán)隊(duì)造成影響
2.訪問(wèn)的作用域和對(duì)象越深,越消耗性能,我們 盡量減少,不過(guò)這并不是硬性的要求,我們盡量減少那些不必要的深入訪問(wèn)。
其他注意點(diǎn)避免隱士類型轉(zhuǎn)換(有時(shí)候判斷需要考慮用全等號(hào)還是雙等號(hào))
var a = 0; if(a === false){ //不執(zhí)行 } if(a == false){ //執(zhí)行了 }
2.盡量少的使用eval()
3.項(xiàng)目發(fā)布時(shí)的代碼壓縮,js文件整合,圖片整合等等優(yōu)化。
4.整個(gè)團(tuán)隊(duì)的代碼書寫風(fēng)格,要確定。
結(jié)束文章基本就寫到這里,項(xiàng)目書寫的注意點(diǎn)不單單只有這些,其實(shí)對(duì)代碼的優(yōu)化還有很多,還有你的經(jīng)驗(yàn)。不斷積累一定會(huì)寫成很優(yōu)雅的代碼。
參考文獻(xiàn):《高性能JavaScript》
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/89328.html
摘要:不單單是因?yàn)橐鸬?。用與要注意的地方這里要注意的是這二個(gè)函數(shù)的第一個(gè)參數(shù)都會(huì)把指向還有第一個(gè)參數(shù)可以為但不要這樣用因?yàn)檫@樣等于自己隱式使用了。 自動(dòng)分號(hào)插入 Js不像其他語(yǔ)言強(qiáng)制要求;號(hào)結(jié)尾不然編譯不過(guò),原因是JS有自動(dòng);號(hào)的插入。 var text=function(){} text() 這樣你不加;號(hào)也能運(yùn)行其實(shí)在內(nèi)部js是需要;號(hào)去幫助解析的 var text=function(...
摘要:解決方式是,當(dāng)我們不使用它們的時(shí)候,手動(dòng)切斷鏈接淘汰把和對(duì)象轉(zhuǎn)為了真正的對(duì)象,避免了使用這種垃圾收集策略,消除了以下常見(jiàn)的內(nèi)存泄漏的主要原因。以上參考資料高程垃圾收集類內(nèi)存泄漏及如何避免內(nèi)存泄露及解決方案詳解類內(nèi)存泄漏及如何避免 showImg(http://ww1.sinaimg.cn/large/005Y4rCogy1ft1ikzcqzqj30ka0et77a.jpg); 前言 起...
摘要:比特幣和以太幣屬于一類區(qū)塊鏈,我們將其歸類為公共無(wú)許可的區(qū)塊鏈技術(shù)。例如,在單個(gè)企業(yè)中部署時(shí),或由受信任的權(quán)威機(jī)構(gòu)運(yùn)作,完全拜占庭容錯(cuò)的共識(shí)可能被認(rèn)為是不必要的,并且對(duì)性能和吞吐量造成過(guò)度的拖累。 介紹 一般而言,區(qū)塊鏈?zhǔn)且粋€(gè)不可變的交易分類賬,維護(hù)在一個(gè)分布式對(duì)等節(jié)點(diǎn)網(wǎng)絡(luò)中。這些節(jié)點(diǎn)通過(guò)應(yīng)用已經(jīng)由共識(shí)協(xié)議驗(yàn)證的交易來(lái)維護(hù)分類帳的副本,該交易被分組為包括將每個(gè)塊綁定到前一個(gè)塊的散列的塊...
閱讀 2584·2021-11-22 09:34
閱讀 959·2021-11-19 11:34
閱讀 2813·2021-10-14 09:42
閱讀 1497·2021-09-22 15:27
閱讀 2396·2021-09-07 09:59
閱讀 1747·2021-08-27 13:13
閱讀 3440·2019-08-30 11:21
閱讀 783·2019-08-29 18:35