您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關如何優化JavaScript的性能,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
話不多說,提到javascript難免會聯想到文檔對象模型(DOM),它作用于XML和HTML文檔的程序接口(API),位于瀏覽器中,主要用來與HTML文檔打交道。同樣也用于Web程序中獲取XML文檔,并使用DOM API來訪問文檔中的數據。盡管DOM是個與語言無關的API,它在瀏覽器中的接口卻是用javascript實現的。客戶端腳本編程大多數時候是在和底層文檔(underlying document) 打交道,DOM就成為現在javascript編程中的重要部分。
瀏覽器通常會把DOM和js獨立實現。比如在IE中,javascript的實現名為Jscript,位于jscript.dll文件中;DOM的實現則存在另一個庫中,名為mshtml.dll(內部稱為Trident)。這個分離允許的其他技術和語言,比如VBScript,能共享使用DOM以及Trident提供的渲染函數。Safari中的DOM和渲染使用的Webkit中的WebCode實現,javascript部分是由獨立的javascriptCode引擎(最新版本的名字為SquirrelFish)來實現。Google Chrome同樣使用WebKit中的WebCore庫來渲染頁面,但javascript引擎是他們自己研發的,名為V8。Firefox的javascript引擎名為SpiderMonkey(最新版的名字為TraceMonkey),與名為Gecko的渲染引擎相互獨立。
把DOM和javascript(這里指ECMAScript,JavaScript使用的ECMAScript版本為ECMAScript-262)各自想象一個島嶼,它們之間用收費橋梁連接。ECMAScript每次訪問DOM,都需要途經這座橋,并交納“過橋費”。訪問DOM的次數越多,費用越高。所以想辦法減少過橋次數就可以減少費用。
一、超載運輸
上面提到“過橋費”很貴啊,那么我們盡量使需要多次去訪問DOM的時候全部整合到一次。比如最簡單的例子:
function innerHTMLLoop(){ for(var count = 0;count < 15000 ;count++){ document.getElementById('here').innerHTML +='a'; } }
這個函數循環修改頁面元素的內容。這段代碼存在循環迭代,該元素都被訪問兩次,一次是讀取innerHTML屬性值,另一次是重寫它。(意味著每次循環都必須付“過橋費”)。
為了減少費用,我們采取一種更高效的方法,例:
function innerHTMLLoop2(){ var content = ' '; for(var count = 0;count < 15000 ;count++){ content +='a'; } document.getElementById('here').innerHTML +=content; }
這樣只需要付一次“過橋費”,就可以完成相同的功能。運行速度在不同的瀏覽器中都有大幅度的提升,例如IE6中,使用innerHTMLLoop2()比使用innerHTMLLoop()快155倍。(所以現實當中好多大卡車超載也是為了省這個費用,一次性多賺點。不過還是量力而行。程序也是一樣,均衡存乎萬物之間。)
二、觸手可及
盡管使用優化過的javascript引擎的新型瀏覽器,對于對象成員引用也存在一些性能問題。對象在原型鏈中存在的未知越深,找到它也就越慢,例如不太常見的寫法:window.location.href。每次遇到點操作符,嵌套成員會導致Javascipt引擎搜索所有對象成員。對象成員嵌套得越深,讀取速度就會越慢。執行location.href總是比window.location.href要快,后者也比window.location.href.toString()要快。如果這些屬性不是對象的實例屬性,那么成員解析還需要搜索原型鏈,這會花更多的時間。
由于類似的性能問題都是與對象成員有關,因此應該盡可能避免使用它們。更準確地說,應當注意,只在必要時使用對象成員。例如,在同一個函數中沒有必要多次讀取同一個對象成員。例:
function hasEitherClass(element,className1,className2){ return element.className == className1 || element.className == className2; }
以上的代碼,element.className讀取了2次。意味著在該函數語句中2次成員查找都是通過讀取屬性值,那么有必要子啊第一次查找到值后就將其存儲在局部變量中,因為局部變量的讀取速度要快很多。例:
function hasEitherClass(element,className1,className2){ var currentClassName = element.className; return currentClassName == className1 || currentClassName == className2; }
上面element.className 賦值在currentClassName局部變量,避免了多次查找帶來的性能開銷。(多次需要全局對象成員,那就賦值在最容易拿到的地方,這樣可以減少去搜索和查找)
總結
雖然我還有很多要講,但是太多太多的方式可以進行性能優化,以后有更好的再補充。不過優化就是跟人找方法用最小的力量去做最大的事情一樣,說俗點就是“懶”,我們讓程序也懶。
下面是一些關于客戶端JS性能的一些優化的小技巧:
1.[頂]關于JS的循環,循環是一種常用的流程控制。JS提供了三種循環:for(;;)、while()、for(in)。在這三種循環中 for(in)的效率最差,因為它需要查詢Hash鍵,因此應盡量少用for(in)循環,for(;;)、while()循環的性能基本持平。當然,推 薦使用for循環,如果循環變量遞增或遞減,不要單獨對循環變量賦值,而應該使用嵌套的++或--運算符。
2.如果需要遍歷數組,應該先緩存數組長度,將數組長度放入局部變量中,避免多次查詢數組長度。
3.局部變量的訪問速度要比全局變量的訪問速度更快,因為全局變量其實是window對象的成員,而局部變量是放在函數的棧里的。
4.盡量少使用eval,每次使用eval需要消耗大量時間,這時候使用JS所支持的閉包可以實現函數模板。
5.盡量避免對象的嵌套查詢,對于obj1.obj2.obj3.obj4這個語句,需要進行至少3次查詢操作,先檢查obj1中是否包含 obj2,再檢查obj2中是否包含obj3,然后檢查obj3中是否包含obj4...這不是一個好策略。應該盡量利用局部變量,將obj4以局部變量 保存,從而避免嵌套查詢。
6.使運算符時,盡量使用+=,-=、*=、\=等運算符號,而不是直接進行賦值運算。
7.[頂]當需要將數字轉換成字符時,采用如下方式:"" + 1。從性能上來看,將數字轉換成字符時,有如下公式:("" +) > String() > .toString() > new String()。String()屬于內部函數,所以速度很快。而.toString()要查詢原型中的函數,所以速度遜色一些,new String()需要重新創建一個字符串對象,速度最慢。
8.[頂]當需要將浮點數轉換成整型時,應該使用Math.floor()或者Math.round()。而不是使用parseInt(),該方法用于將字符串轉換成數字。而且Math是內部對象,所以Math.floor()其實并沒有多少查詢方法和調用時間,速度是最快的。
9.盡量作用JSON格式來創建對象,而不是var obj=new Object()方法。因為前者是直接復制,而后者需要調用構造器,因而前者的性能更好。
10.當需要使用數組時,也盡量使用JSON格式的語法,即直接使用如下語法定義數組:[parrm,param,param...],而不是采用 new Array(parrm,param,param...)這種語法。因為使用JSON格式的語法是引擎直接解釋的。而后者則需要調用Array的構造器。
11.[頂]對字符串進行循環操作,例如替換、查找,就使用正則表達式。因為JS的循環速度比較慢,而正則表達式的操作是用C寫成的API,性能比較好。
最后有一個基本原則,對于大的JS對象,因為創建時時間和空間的開銷都比較大,因此應該盡量考慮采用緩存。
上述就是小編為大家分享的如何優化JavaScript的性能了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。