日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問(wèn)題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
技術(shù)進(jìn)階:通過(guò)來(lái)JavaScript性能調(diào)優(yōu)提高Web應(yīng)用性能

[[219300]]

前言

現(xiàn)在的互聯(lián)網(wǎng)應(yīng)用中,在Web 開(kāi)發(fā)中經(jīng)常會(huì)遇到性能的問(wèn)題,尤其是針對(duì)當(dāng)今的 Web2.0 +應(yīng)用。JavaScript 是當(dāng)今使用最為廣泛的 Web 開(kāi)發(fā)語(yǔ)言,Web 應(yīng)用的性能問(wèn)題很大一部分都是由程序員寫(xiě)的 JavaScript 腳本性能不佳所造成的,里面包括了 JavaScript 語(yǔ)言本身的性能問(wèn)題,以及其與 DOM 交互時(shí)的性能問(wèn)題。本文主要來(lái)探討一下如何盡可能多的避免這類問(wèn)題,從而最大限度的提高 Web 應(yīng)用的性能。

成都創(chuàng)新互聯(lián)堅(jiān)持“要么做到,要么別承諾”的工作理念,服務(wù)領(lǐng)域包括:成都網(wǎng)站設(shè)計(jì)、網(wǎng)站建設(shè)、外貿(mào)網(wǎng)站建設(shè)、企業(yè)官網(wǎng)、英文網(wǎng)站、手機(jī)端網(wǎng)站、網(wǎng)站推廣等服務(wù),滿足客戶于互聯(lián)網(wǎng)時(shí)代的天元網(wǎng)站設(shè)計(jì)、移動(dòng)媒體設(shè)計(jì)的需求,幫助企業(yè)找到有效的互聯(lián)網(wǎng)解決方案。努力成為您成熟可靠的網(wǎng)絡(luò)建設(shè)合作伙伴!

1.JavaScript 性能調(diào)優(yōu)

JavaScript 語(yǔ)言由于它的單線程和解釋執(zhí)行的兩個(gè)特點(diǎn),決定了它本身有很多地方有性能問(wèn)題,所以可改進(jìn)的地方有不少。

1.1 eval 的問(wèn)題:

比較下述代碼:

清單 1. eval 的問(wèn)題

有"eval"的代碼比沒(méi)有"eval"的代碼要慢上 100 倍以上。

主要原因是:JavaScript 代碼在執(zhí)行前會(huì)進(jìn)行類似"預(yù)編譯"的操作:首先會(huì)創(chuàng)建一個(gè)當(dāng)前執(zhí)行環(huán)境下的活動(dòng)對(duì)象,并將那些用 var 申明的變量設(shè)置為活動(dòng)對(duì)象的屬性,但是此時(shí)這些變量的賦值都是 undefined,并將那些以 function 定義的函數(shù)也添加為活動(dòng)對(duì)象的屬性,而且它們的值正是函數(shù)的定義。但是,如果你使用了"eval",則"eval"中的代碼(實(shí)際上為字符串)無(wú)法預(yù)先識(shí)別其上下文,無(wú)法被提前解析和優(yōu)化,即無(wú)法進(jìn)行預(yù)編譯的操作。所以,其性能也會(huì)大幅度降低。

1.2 Function 的用法

比較下述代碼:

清單 2. function 的用法

這里類似之前提到的"eval"方法,這里"func1"的效率會(huì)比"func2"的效率差很多,所以推薦使用第二種方式。

1.3函數(shù)的作用域鏈(scope chain)

JavaScript 代碼解釋執(zhí)行,在進(jìn)入函數(shù)內(nèi)部時(shí),它會(huì)預(yù)先分析當(dāng)前的變量,并將這些變量歸入不同的層級(jí)(level),一般情況下:

局部變量放入層級(jí) 1(淺),全局變量放入層級(jí) 2(深)。如果進(jìn)入"with"或"try – catch"代碼塊,則會(huì)增加新的層級(jí),即將"with"或"catch"里的變量放入最淺層(層 1),并將之前的層級(jí)依次加深。

參考如下代碼:

清單 3. 函數(shù)作用域鏈

這里我們可以看到,"images","widget","combination"屬于局部變量,在層 1。"document","myObj"屬于全局變量,在層 2。

變量所在的層越淺,訪問(wèn)(讀取或修改)速度越快,層越深,訪問(wèn)速度越慢。所以這里對(duì)"images","widget","combination"的訪問(wèn)速度比"document","myObj"要快一些。所以推薦盡量使用局部變量,可見(jiàn)如下代碼:

清單 4. 使用局部變量

我們用局部變量"doc"取代全局變量"document",這樣可以改進(jìn)性能,尤其是對(duì)于大量使用全局變量的函數(shù)里面。

再看如下代碼:

清單 5. 慎用 with

加上"with"關(guān)鍵字,我們讓代碼更加簡(jiǎn)潔清晰了,但是這樣做性能會(huì)受影響。正如之前說(shuō)的,當(dāng)我們進(jìn)入"with"代碼塊時(shí),"combination"便從原來(lái)的層 1 變到了層 2,這樣,效率會(huì)大打折扣。所以比較一下,還是使用原來(lái)的代碼:

清單 6. 改進(jìn) with

但是這樣并不是最好的方式,JavaScript 有個(gè)特點(diǎn),對(duì)于 object 對(duì)象來(lái)說(shuō),其屬性訪問(wèn)層級(jí)越深,效率越低,比如這里的"myObj"已經(jīng)訪問(wèn)到了第 3 層,我們可以這樣改進(jìn)一下:

清單 7. 縮小對(duì)象訪問(wèn)層級(jí)

我們用局部變量來(lái)代替"myObj"的第 2 層的"container"對(duì)象。如果有大量的這種對(duì)對(duì)象深層屬性的訪問(wèn),可以參照以上方式提高性能。

1.4字符串(String)相關(guān)

字符串拼接

經(jīng)常看到這樣的代碼:

清單 8. 字符串簡(jiǎn)單拼接

str += "str1" + "str2"

這是我們拼接字符串常用的方式,但是這種方式會(huì)有一些臨時(shí)變量的創(chuàng)建和銷毀,影響性能,所以推薦使用如下方式拼接:

清單 9. 字符串?dāng)?shù)組方式拼接

var str_array = [];

str_array.push("str1");

str_array.push("str2");

str = str_array.join("");

這里我們利用數(shù)組(array)的"join"方法實(shí)現(xiàn)字符串的拼接,尤其是程序的老版本的 Internet Explore(IE6)上運(yùn)行時(shí),會(huì)有非常明顯的性能上的改進(jìn)。

當(dāng)然,最新的瀏覽器(如火狐 Firefox3+,IE8+ 等等)對(duì)字符串的拼接做了優(yōu)化,我們也可以這樣寫(xiě):

清單 10. 字符串快速拼接

str +="str1"

str +="str2"

新的瀏覽器對(duì)"+="做了優(yōu)化,性能略快于數(shù)組的"join"方法。在不久的將來(lái)更新版本瀏覽器可能對(duì)"+"也會(huì)做優(yōu)化,所以那時(shí)我們可以直接寫(xiě):str += "str1" + "str2"。

隱式類型轉(zhuǎn)換

參考如下代碼:

清單 11. 隱式類型轉(zhuǎn)換

這里我們?cè)诿總€(gè)循環(huán)時(shí)都會(huì)調(diào)用字符串的"charAt"方法,但是由于我們是將常量"12345678"賦值給"str",所以"str"這里事實(shí)上并不是一個(gè)字符串對(duì)象,當(dāng)它每次調(diào)用"charAt"函數(shù)時(shí),都會(huì)臨時(shí)構(gòu)造值為"12345678"的字符串對(duì)象,然后調(diào)用"charAt"方法,最后再釋放這個(gè)字符串臨時(shí)對(duì)象。我們可以做一些改進(jìn):

清單 12. 避免隱式類型轉(zhuǎn)換

這樣一來(lái),變量"str"作為一個(gè)字符串對(duì)象,就不會(huì)有這種隱式類型轉(zhuǎn)換的過(guò)程了,這樣一來(lái),效率會(huì)顯著提高。

字符串匹配

JavaScript 有 RegExp 對(duì)象,支持對(duì)字符串的正則表達(dá)式匹配。是一個(gè)很好的工具,但是它的性能并不是非常理想。相反,字符串對(duì)象(String)本身的一些基本方法的效率是非常高的,比如"substring","indexOf","charAt"等等,在我們需要用正則表達(dá)式匹配字符串時(shí),可以考慮一下:

1)是否能夠通過(guò)字符串對(duì)象本身支持的基本方法解決問(wèn)題。

2)是否可以通過(guò)"substring"來(lái)縮小需要用正則表達(dá)式的范圍。

這些方式都能夠有效的提高程序的效率。

關(guān)于正則表達(dá)式對(duì)象,還有一點(diǎn)需要注意,參考如下代碼:

清單 13. 正則表達(dá)式

這里,我們往"match"方法傳入"/^s*extras/"是會(huì)影響效率的,它會(huì)構(gòu)建臨時(shí)值為"/^s*extras/"的正則表達(dá)式對(duì)象,執(zhí)行"match"方法,然后銷毀臨時(shí)的正則表達(dá)式對(duì)象。我們可以這樣做:

清單 14. 利用變量

這樣就不會(huì)有臨時(shí)對(duì)象了。

setTimeout 和 setInterval

"setTimeout"和"setInterval"這兩個(gè)函數(shù)可以接受字符串變量,但是會(huì)帶來(lái)與之前談到的"eval"類似的性能問(wèn)題,所以建議還是直接傳入函數(shù)對(duì)象本身。

利用提前退出

參考如下兩段代碼:

清單 15. 利用提前退出

代碼 2 多了一個(gè)對(duì)"name.indexOf( … )"的判斷,這使得程序每次走到這一段時(shí)會(huì)先執(zhí)行"indexOf"的判斷,再執(zhí)行后面的"match",在"indexOf"比"match"效率高很多的前提下,這樣做會(huì)減少"match"的執(zhí)行次數(shù),從而一定程度的提高效率。

2. DOM 操作性能調(diào)優(yōu)

JavaScript 的開(kāi)發(fā)離不開(kāi) DOM 的操作,所以對(duì) DOM 操作的性能調(diào)優(yōu)在 Web 開(kāi)發(fā)中也是非常重要的。

2.1 Repaint 和 Reflow

Repaint 也叫 Redraw,它指的是一種不會(huì)影響當(dāng)前 DOM 的結(jié)構(gòu)和布局的一種重繪動(dòng)作。如下動(dòng)作會(huì)產(chǎn)生 Repaint 動(dòng)作:

不可見(jiàn)到可見(jiàn)(visibility 樣式屬性)

顏色或圖片變化(background, border-color, color 樣式屬性)

不改變頁(yè)面元素大小,形狀和位置,但改變其外觀的變化

Reflow 比起 Repaint 來(lái)講就是一種更加顯著的變化了。它主要發(fā)生在 DOM 樹(shù)被操作的時(shí)候,任何改變 DOM 的結(jié)構(gòu)和布局都會(huì)產(chǎn)生 Reflow。但一個(gè)元素的 Reflow 操作發(fā)生時(shí),它的所有父元素和子元素都會(huì)放生 Reflow,最后 Reflow 必然會(huì)導(dǎo)致 Repaint 的產(chǎn)生。舉例說(shuō)明,如下動(dòng)作會(huì)產(chǎn)生 Repaint 動(dòng)作:

瀏覽器窗口的變化

DOM 節(jié)點(diǎn)的添加刪除操作

一些改變頁(yè)面元素大小,形狀和位置的操作的觸發(fā)

2.2 減少 Reflow

通過(guò) Reflow 和 Repaint 的介紹可知,每次 Reflow 比其 Repaint 會(huì)帶來(lái)更多的資源消耗,我們應(yīng)該盡量減少 Reflow 的發(fā)生,或者將其轉(zhuǎn)化為只會(huì)觸發(fā) Repaint 操作的代碼。

參考如下代碼:

清單 16. reflow 介紹

這是我們經(jīng)常接觸的代碼了,但是這段代碼會(huì)產(chǎn)生 3 次 reflow。再看如下代碼:

清單 17. 減少 reflow

這里便只有一次 reflow,所以我們推薦這種 DOM 節(jié)點(diǎn)操作的方式。

關(guān)于上述較少 Reflow 操作的解決方案,還有一種可以參考的模式:

清單 18. 利用 display 減少 reflow

先隱藏 pDiv,再顯示,這樣,隱藏和顯示之間的操作便不會(huì)產(chǎn)生任何的 Reflow,提高了效率。

2.3特殊測(cè)量屬性和方法

DOM 元素里面有一些特殊的測(cè)量屬性的訪問(wèn)和方法的調(diào)用,也會(huì)觸發(fā) Reflow,比較典型的就是"offsetWidth"屬性和"getComputedStyle"方法。

圖 1. 特殊測(cè)量屬性和方法

這些測(cè)量屬性和方法大致有這些:

· offsetLeft

· offsetTop

· offsetHeight

· offsetWidth

· scrollTop/Left/Width/Height

· clientTop/Left/Width/Height

· getComputedStyle()

· currentStyle(in IE))

這些屬性和方法的訪問(wèn)和調(diào)用,都會(huì)觸發(fā) Reflow 的產(chǎn)生,我們應(yīng)該盡量減少對(duì)這些屬性和方法的訪問(wèn)和調(diào)用,參考如下代碼:

清單 19. 特殊測(cè)量屬性

這里我們可以用臨時(shí)變量將"offsetWidth"的值緩存起來(lái),這樣就不用每次訪問(wèn)"offsetWidth"屬性。這種方式在循環(huán)里面非常適用,可以極大地提高性能。

2.4 樣式相關(guān)

我們肯定經(jīng)常見(jiàn)到如下的代碼:

清單 20. 樣式相關(guān)

但是可以看到,這里的每一個(gè)樣式的改變,都會(huì)產(chǎn)生 Reflow。需要減少這種情況的發(fā)生,我們可以這樣做:

解決方案 1:

清單 21. className 解決方案

用 class 替代 style,可以將原有的所有 Reflow 或 Repaint 的次數(shù)都縮減到一個(gè)。

解決方案 2:

清單 22. cssText 解決方案

一次性設(shè)置所有樣式,也是減少 Reflow 提高性能的方法。

2.5 XPath

一個(gè)頁(yè)面上往往包含 1000 多頁(yè)面元素,在定位具體元素的時(shí)候,往往需要一定的時(shí)間。如果用 id 或 name 定位可能效率不會(huì)太慢,如果用元素的一些其他屬性(比如 className 等等)定位,可能效率有不理想了。有的可能只能通過(guò)遍歷所有元素(getElementsByTagName)然后過(guò)濾才能找到相應(yīng)元素,這就更加低效了,這里我們推薦使用 XPath 查找元素,這是很多瀏覽器本身支持的功能。

清單 23. XPath 解決方案

瀏覽器 XPath 的搜索引擎會(huì)優(yōu)化搜索效率,大大縮短結(jié)果返回時(shí)間。

2.6 HTMLCollection 對(duì)象

這是一類特殊的對(duì)象,它們有點(diǎn)像數(shù)組,但不完全是數(shù)組。下述方法的返回值一般都是 HTMLCollection 對(duì)象:

· document.images, document.forms

· getElementsByTagName()

· getElementsByClassName()

這些 HTMLCollection 對(duì)象并不是一個(gè)固定的值,而是一個(gè)動(dòng)態(tài)的結(jié)果。它們是一些比較特殊的查詢的返回值,在如下情況下,它們會(huì)重新執(zhí)行之前的查詢而得到新的返回值(查詢結(jié)果),雖然多數(shù)情況下會(huì)和前一次或幾次的返回值都一樣:

· Length 屬性

· 具體的某個(gè)成員

所以,HTMLCollection 對(duì)象對(duì)這些屬性和成員的訪問(wèn),比起數(shù)組來(lái)要慢很多。當(dāng)然也有例外,Opera 和 Safari 對(duì)這種情況就處理的很好,不會(huì)有太大性能問(wèn)題。

參考如下代碼:

清單 24. HTMLConnection 對(duì)象

上述兩端代碼,下面的效率比起上面一段要慢很多,因?yàn)槊恳粋€(gè)循環(huán)都會(huì)有"items.length"的觸發(fā),也就會(huì)導(dǎo)致"document.getElementsByTagName(..)"方法的再次調(diào)用,這便是效率便會(huì)大幅度下降的原因。我們可以這樣解決:

清單 25. HTMLConnection 對(duì)象解決方案

這樣一來(lái),效率基本與普通數(shù)組一樣。

2.7 動(dòng)態(tài)創(chuàng)建 script 標(biāo)簽

加載并執(zhí)行一段 JavaScript 腳本是需要一定時(shí)間的,在我們的程序中,有時(shí)候有些 JavaScript 腳本被加載后基本沒(méi)有被使用過(guò) (比如:腳本里的函數(shù)從來(lái)沒(méi)有被調(diào)用等等)。加載這些腳本只會(huì)占用 CPU 時(shí)間和增加內(nèi)存消耗,降低 Web 應(yīng)用的性能。所以推薦動(dòng)態(tài)的加載 JavaScript 腳本文件,尤其是那些內(nèi)容較多,消耗資源較大的腳本文件。

清單 26. 創(chuàng)建 script 標(biāo)簽

寫(xiě)在最后

這篇文章介紹了 Web 開(kāi)發(fā)中關(guān)于性能方面需要注意的一些小細(xì)節(jié),從 JavaScript 本身著手,介紹了 JavaScript 中需要避免的一些函數(shù)的使用和編程規(guī)則,比如 eval 的弊端,function scope chain 以及 String 的用法等等,也分享了一些比較推薦的做法,并擴(kuò)展到 JavaScript 對(duì) DOM 操作的性能調(diào)優(yōu),比如利用 Repaint 和 Reflow 的機(jī)制,如何使用特殊測(cè)量屬性,樣式相關(guān)的性能調(diào)優(yōu)以及 HTMLCollection 對(duì)象的原理和使用小技巧。這些小細(xì)節(jié)我們可以在開(kāi)發(fā)過(guò)程中盡量注意一下,以盡可能多的提高我們 Web 應(yīng)用的性能。


當(dāng)前標(biāo)題:技術(shù)進(jìn)階:通過(guò)來(lái)JavaScript性能調(diào)優(yōu)提高Web應(yīng)用性能
網(wǎng)站網(wǎng)址:http://m.5511xx.com/article/dpidihj.html