js性能优化--学习笔记
《高性能網(wǎng)站建設(shè)進(jìn)階指南》:
1.使用局部變量,避免深入作用域查找,局部變量是讀寫(xiě)速度最快的;把函數(shù)中使用次數(shù)超過(guò)一次的對(duì)象屬性和數(shù)組存儲(chǔ)為局部變量是一個(gè)好方法;比如for循環(huán)中的.length通常可以保存為局部變量。
2,多個(gè)if時(shí),if順序按概率降序排列
3,當(dāng)僅判斷一兩個(gè)條件時(shí),if通常比switch更快,當(dāng)有兩個(gè)以上條件且條件比較簡(jiǎn)單(不是范圍判定)時(shí),switch通常更快;因?yàn)槎鄶?shù)情況下,switch語(yǔ)句中執(zhí)行單個(gè)條件的時(shí)間比if短;
4,循環(huán)中把循環(huán)變量遞減到0,而不是遞增到長(zhǎng)度,把條件改成了與0比較,速度更快,如for(var i=arr.length;i--){};
5,避免for in;for in是用來(lái)遍歷對(duì)象的可枚舉屬性,需要遍歷整個(gè)原型鏈來(lái)查找可枚舉屬性,若
Array.prototype.myf=function(){};//(數(shù)據(jù)屬性默認(rèn)都是可枚舉的)
var a=['a','b'];for(var p in a){console.log(p+','+a[p]);}
輸出將是:
0,a
1,b
myf,function (){}
對(duì)于object同樣如此,所以一般需要用hasOwnProperty來(lái)確保只變例對(duì)象實(shí)例自身的屬性。
若已知對(duì)象的屬性,則采用普通的for循環(huán)性能優(yōu)于for in;如var arr=['p1','p2','p3'];for(){process(obj[arr[i]]);}
6,性能優(yōu)化:拆分js,減少初次render的下載量,注意會(huì)出現(xiàn)用戶點(diǎn)擊時(shí),事件綁定還沒(méi)完成的情況。js延遲下載;
7,css選擇符;匹配順序是從右到左的;避免通配符,用classname代替標(biāo)簽名,利用屬性繼承。。。。。。
?
《高性能javascript》:
?V8 引擎由以下幾個(gè)核心部分組成:
- 基本編譯器(base compiler),在你的代碼運(yùn)行之前,它會(huì)分析你的 JavaScript 代碼并生成本地機(jī)器碼,而不是執(zhí)行字節(jié)碼或簡(jiǎn)單地解釋它。這種機(jī)器碼起初是沒(méi)有被高度優(yōu)化的。
- V8 將對(duì)象解析為對(duì)象模型(object model)。對(duì)象是在 JavaScript 中是以關(guān)聯(lián)數(shù)組的方式呈現(xiàn)的,但是在 V8 引擎中,它們是通過(guò)隱藏類(lèi)(hidden classes)的方式來(lái)表示的。這是一種可以優(yōu)化查找的內(nèi)部類(lèi)型機(jī)制。
- 一個(gè)運(yùn)行時(shí)分析器(runtime profiler),它監(jiān)視正在運(yùn)行的系統(tǒng),并標(biāo)識(shí) “hot” 函數(shù),也就是那些最后會(huì)花費(fèi)大量運(yùn)行時(shí)間的代碼。
- 一個(gè)優(yōu)化編譯器(optimizing compiler),它重新編譯和優(yōu)化那些被運(yùn)行時(shí)分析器標(biāo)識(shí)為 “hot” 的代碼,并進(jìn)行 “內(nèi)聯(lián)” 等優(yōu)化(例如,在函數(shù)被調(diào)用的地方用函數(shù)主體去取代)。
- V8支持逆優(yōu)化(deoptimization),這意味著,如果優(yōu)化編譯器發(fā)現(xiàn)在某些假定的情況下,把一些已經(jīng)優(yōu)化的代碼進(jìn)行了過(guò)度的優(yōu)化,它會(huì)舍棄優(yōu)化后的代碼。
- 垃圾回收器,理解它的運(yùn)作原理和理解如何優(yōu)化你的JavaScript代碼同等重要。
垃圾回收是內(nèi)存管理的一種機(jī)制,垃圾回收器的概念是,它將試圖回收那些不再被使用的對(duì)象所占據(jù)的內(nèi)存,在像 JavaScript 這種支持垃圾回收的語(yǔ)言中,如果程序中仍然存在指向一個(gè)對(duì)象的引用,那么該對(duì)象將不會(huì)被回收。
在大多數(shù)情況下,我們沒(méi)有必要去手動(dòng)得解除對(duì)象的引用(de-referencing)。只需要簡(jiǎn)單滴將變量放在需要它們的位置(在理想的情況下,盡可能使用局部變量,也就是說(shuō),在它們被使用的函數(shù)中聲明它們,而不是在更外層的作用域),垃圾就能正確地被回收。
在 JavaScript 中,強(qiáng)制進(jìn)行垃圾回收是不可能的,而且你也不應(yīng)該嘗試這樣做,因?yàn)槔厥帐怯蛇\(yùn)行時(shí)控制,并且它通常知道垃圾回收的最佳時(shí)機(jī)。在可能的情況下,盡量避免使用?delete,
盡管如此,你肯定會(huì)發(fā)在許多流行的 JavaScript 庫(kù)中使用了 delete - 這有它語(yǔ)言目的。這里的主旨是,避免在運(yùn)行時(shí)修改 “hot” 對(duì)象的結(jié)構(gòu),JavaScript 引擎可以檢測(cè)到這些 “hot” 的對(duì)象,并嘗試對(duì)其進(jìn)行優(yōu)化。如果在對(duì)象的生命期中沒(méi)有遇到重大的結(jié)構(gòu)改變,引擎的檢測(cè)和優(yōu)化過(guò)程會(huì)來(lái)得更加容易,而使用?delete?則會(huì)觸發(fā)對(duì)象結(jié)構(gòu)上的這種改變。
不少人對(duì)?null?的使用上也存在誤解。將一個(gè)對(duì)象引用設(shè)置為?null,并不是意味著“清空”該對(duì)象,只是將它的引用指向?null。使用?o.x = null?比使用?delete?會(huì)更好些,但這甚至可能也是不必要的。
如果此引用是當(dāng)前對(duì)象的最后引用,那么該對(duì)象就滿足了垃圾回收的資格。如果此引用不是當(dāng)前對(duì)象的最后引用,則該對(duì)象是可訪問(wèn)的,而不會(huì)被垃圾回收。
另外需要注意的是,全局變量在頁(yè)面的生命周期中是不會(huì)被垃圾回收器清理的。只要頁(yè)面保持打開(kāi)狀態(tài),全局對(duì)象就會(huì)常駐在內(nèi)存當(dāng)中。只有當(dāng)刷新頁(yè)面、導(dǎo)航到其他頁(yè)面、關(guān)閉標(biāo)簽頁(yè)或退出瀏覽器時(shí),全局變量才會(huì)被清理。函數(shù)作用域的變量超出作用域范圍時(shí),它就會(huì)被清理。當(dāng)函數(shù)完全結(jié)束,并且再?zèng)]有任何引用指向其中的變量,函數(shù)中的變量會(huì)被清理。
經(jīng)驗(yàn)法則:
為了使垃圾回收器盡早回收盡可能多的對(duì)象,請(qǐng)不要保留(hold on)不再需要的對(duì)象。(qi:比如在函數(shù)里return一個(gè)不需要的變量,因?yàn)檫@會(huì)導(dǎo)致變量不會(huì)被回收)這里有幾點(diǎn)需要謹(jǐn)記:
- 就像之前所說(shuō)的那樣,比手動(dòng)刪除變量引用更好的方式是,在恰當(dāng)?shù)淖饔糜蛑惺褂米兞?#xff0c;例如,盡量在函數(shù)作用域中聲明變量,而盡可能不要聲明不會(huì)被回收的全局變量,這將意味著更干凈更省心的代碼。
- 確保解綁那些不再需要的事件監(jiān)聽(tīng)器,尤其是那些即將被移除的 DOM 對(duì)象所綁定的事件。
- 如果你正在使用數(shù)據(jù)緩存,確保手動(dòng)清理緩存或者使用衰老機(jī)制,避免緩存中儲(chǔ)存大量不會(huì)被重用的數(shù)據(jù)。
數(shù)組字面量非常有用,它可以暗示數(shù)組的大小和類(lèi)型。它通常用在體積不大的數(shù)組中。
| ? | // V8 知道你需要一個(gè)長(zhǎng)度為 4 并且儲(chǔ)存數(shù)字的數(shù)組: var a = [1, 2, 3, 4]; // 不要這樣做: a = []; // V8 將對(duì)數(shù)組一無(wú)所知 for(var i = 1; i <= 4; i++) { a.push(i); } |
qi:閉包也會(huì)導(dǎo)致變量不會(huì)被回收,事件委托:$('table').on('click',?td,?...)優(yōu)于$('table?td').on('click', ...)
當(dāng)瀏覽器重新渲染文檔中的元素時(shí)需要重新計(jì)算它們的位置和幾何形狀時(shí),我們稱(chēng)之為回流。回流會(huì)阻塞用戶在瀏覽器中的操作,因此理解提升回流時(shí)間是非常有幫助的。使用document.createDocumentFragment()創(chuàng)建了一虛擬的節(jié)點(diǎn)對(duì)象(節(jié)點(diǎn)對(duì)象包含所有屬性和方法),保存多個(gè)小節(jié)點(diǎn)后在append;在所有節(jié)點(diǎn)類(lèi)型中,只有文檔片段DocumentFragment在文檔中沒(méi)有對(duì)應(yīng)的標(biāo)記。DOM規(guī)定文檔片段(documentfragment)是一種”輕量級(jí)“的文檔,可以包含和控制節(jié)點(diǎn),但不會(huì)像完整的文檔那樣占用額外資源。即當(dāng)請(qǐng)求把一個(gè) DocumentFragment 節(jié)點(diǎn)插入文檔樹(shù)時(shí),插入的不是 DocumentFragment 自身,而是它的所有子孫節(jié)點(diǎn)。這使得 DocumentFragment 成了有用的占位符,暫時(shí)存放那些一次插入文檔的節(jié)點(diǎn)。它還有利于實(shí)現(xiàn)文檔的剪切、復(fù)制和粘貼操作,尤其是與 Range 接口一起使用時(shí)更是如此.
qi: css性能:盡量repaint而不是reflow.
顯式設(shè)置圖片的寬高:
當(dāng)瀏覽器加載頁(yè)面的HTML代碼時(shí),有時(shí)候需要在圖片下載完成前就對(duì)頁(yè)面布局進(jìn)行定位。如果HTML里的圖片沒(méi)有指定尺寸(寬和高),或者代碼描述的尺寸與實(shí)際圖片的尺寸不符時(shí),瀏覽器則要在圖片下載完成后再“回溯”該圖片并重新顯示,這會(huì)消耗額外時(shí)間。所以,最好為頁(yè)面里的每一張圖片都指定尺寸,不管是在頁(yè)面HTML里的<img>標(biāo)簽,還是在CSS里。
瀏覽器解析頁(yè)面順序:參考http://www.alloyteam.com/2015/05/wang-ye-xing-neng-zhi-html-css-javascript/;
qi:瀏覽器得到某個(gè)頁(yè)面后,按順序開(kāi)始解析,遇到css file和image,發(fā)相應(yīng)的請(qǐng)求,同時(shí)繼續(xù)往下,到結(jié)束就構(gòu)建好了無(wú)樣式的dom tree,css file下載后解析得到CSSOM,結(jié)合dom tree開(kāi)始渲染得到render tree,至此在chrome developer tool里就是domComplete完成的時(shí)間(藍(lán)色豎線),等image下載好插入render tree,至此在chrome developer tool里就是domLoader完成的時(shí)間(紅色豎線).因?yàn)閖s有可能改變dom tree結(jié)構(gòu),所以如果遇到j(luò)s file會(huì)暫時(shí)停止其他渲染行為,等js解析完成后再渲染。?使用async標(biāo)識(shí)的javascript,瀏覽器將異步執(zhí)行javascript不會(huì)阻塞正常的dom渲染。
轉(zhuǎn)載于:https://www.cnblogs.com/yigeqi/p/4598771.html
總結(jié)
以上是生活随笔為你收集整理的js性能优化--学习笔记的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 信用卡临时额度怎么转固定额度?二者有什么
- 下一篇: 如何在PowerDesigner将PDM