加勒比HEZYO黑人专区-久久精品国产99国产精品亚洲-精品国产18久久久久久-久久人妻少妇嫩草AV

歡迎光臨 織晶網(wǎng)絡(luò)官網(wǎng)!

  • 服務(wù)支持
  • 020-39182790
技術(shù)文檔您現(xiàn)在的位置:首頁(yè) > 服務(wù)支持 > 技術(shù)文檔

JavaScript性能優(yōu)化之網(wǎng)站應(yīng)用

作者:織晶客服部   發(fā)布于:2020/12/24 10:06:02  點(diǎn)擊量:  來(lái)源:織晶網(wǎng)絡(luò)

網(wǎng)站性能是創(chuàng)建網(wǎng)頁(yè)或應(yīng)用程序時(shí)最重要的一個(gè)方面。沒(méi)有人想要應(yīng)用程序崩潰或者網(wǎng)頁(yè)無(wú)法加載,或者用戶的等待時(shí)間過(guò)長(zhǎng)。可以從日常的業(yè)務(wù)邏輯出發(fā),去優(yōu)化和提升網(wǎng)站的應(yīng)用性能,特別是JavaScript性能優(yōu)化。


1:垃圾收集

 

日常中的某些情況下垃圾收集器無(wú)法回收無(wú)用變量,導(dǎo)致的一個(gè)結(jié)果就是——內(nèi)存使用率不斷增高,以下為對(duì)應(yīng)的情況以及處理方法。

 

①對(duì)象相互引用會(huì)導(dǎo)致引用計(jì)數(shù)始終為2,所以用完對(duì)象后應(yīng)將引用設(shè)為null,例子如下

let element = document.getElementById("test"); let myObject = new Object();
myObject.element = element;
element.someObject = myObject;

//....用完后需要加如下代碼
myObject.element = null;
element.someObject = null;

 

②當(dāng)數(shù)據(jù)不再有用時(shí),需要通過(guò)將值設(shè)為null來(lái)解除引用,該做法適用于大多數(shù)全局變量和全局對(duì)象屬性,例子如下

function createPerson(name){
    let localPerson = new Object();
    localPerson.name = name; return localPerson
}

let globalPerson = createPerson("test") //...用完后手動(dòng)解除 globalPerson = null

 

③關(guān)于與閉包相關(guān)的內(nèi)存泄漏如下

function assignHandler(){
  let element = document.getElementById("test");
  element.onclick = function(){
    alert(element.id)    
  }          
} //以上會(huì)導(dǎo)致element的引用數(shù)無(wú)法被回收,更改如下 function assignHandler(){
  let element = document.getElementById("test");
  let id = element.id;
  
  element.onclick = function(){
    alert(id)
  }          
  element = null;  
}

 


 

2:事件委托

 

在js中,添加到頁(yè)面上的事件處理程序數(shù)量會(huì)直接關(guān)系到頁(yè)面整體運(yùn)行運(yùn)行性能。導(dǎo)致這一問(wèn)題的原因是多方面的。首先函數(shù)都是對(duì)象,都會(huì)占用內(nèi)存;內(nèi)存中對(duì)象越多,性能就越差。其次,必須事先指定所有事件處理程序而導(dǎo)致的DOM訪問(wèn)次數(shù),會(huì)延遲整個(gè)頁(yè)面的交互就緒時(shí)間。以下為對(duì)應(yīng)的情況以及處理方法

 

①同類型的事件處理函數(shù)過(guò)多時(shí),應(yīng)該結(jié)合為一個(gè),例子如下:

//html代碼 ul id="myLinks"
    li id="goSomeWhere">Go somewhereSay hi//分別加上事件處理-JS代碼 let item1 = document.getElementById("goSomeWhere");
let item2 = document.getElementById("sayHi");

EventUtil.addHandler(item1, "click", function(event){
  console.log("goSomeWhere")  
}

EventUtil.addHandler(item2, "click", function(event){
  console.log("sayHi");  
} //改善點(diǎn)即將click事件結(jié)合在一起 let list = document.getElementById("myLinks")

EventUtil.addHandler(list, "click", function(event){
  event = EventUtil.getEvent(event);
  let target = EventUtil.getTarget(event); switch(target.id){ case "goSomeWhere":
      console.log("goSomeWhere"); break; case "sayHi":
      console.log("sayHi"); break;            
  }     
}

 

②內(nèi)存留有過(guò)時(shí)不用的“空事件處理程序”也是造成性能問(wèn)題的主因,兩種情況下會(huì)造成該問(wèn)題。運(yùn)用removeChild()和replaceChild()方法去除節(jié)點(diǎn)時(shí);在使用innerHTML替換頁(yè)面某一部分時(shí),如果帶有事件處理程序的元素被innerHTML刪除了,那么原有事件處理函數(shù)極有可能無(wú)法被回收,例子如下

//例子中id為myBtn的點(diǎn)擊事件變?yōu)榱丝帐录幚沓绦?/span> div id="myDiv"
    input type="button" value="Click Me" id="myBtn"
/div
script type="text/javascript"  let btn = document.getElementById("myBtn");
    btn.onclick = function(){
      document.getElementById("myDiv").innerHTML = "xxxx";  
    }; //改善點(diǎn)即需要手工移除事件處理程序 div id="myDiv"
    input type="button" value="Click Me" id="myBtn"
/div
script type="text/javascript"  let btn = document.getElementById("myBtn");
    btn.onclick = function(){
      btn.onclick = null;
      document.getElementById("myDiv").innerHTML = "xxxx";  
    }; /script

 


 

3:注意作用域

 

關(guān)于作用域鏈,我們明白訪問(wèn)全局變量會(huì)比訪問(wèn)局部變量要慢

 

①若某處循環(huán)使用全局變量時(shí),我們可以略做修改,例子如下

//假設(shè)有多個(gè)img標(biāo)簽的內(nèi)容,循環(huán)中引用了多次document全局變量 function updateUI(){
  let imgs = document.getElementsByTagName("img") for (let i = 0; len = imgs.length; i < len; ++i){
    imgs[i].title = document.title + " image “ + i  
  }    

  let msg = document.getElementById("msg");
  msg.innerHTML = "Update";    
}

//改善點(diǎn)
function updateUI(){
  let doc = document
  let imgs = doc.getElementsByTagName("img")
  for (let i = 0; len = imgs.length; i < len; ++i){
    imgs[i].title = doc.title + " image “ + i  
  }    

  let msg = doc.getElementById("msg");
  msg.innerHTML = "Update";    
}

 

②盡量少用with,因?yàn)閣ith會(huì)增加其中執(zhí)行代碼的作用域鏈的長(zhǎng)度

 


 

4:選擇正確方法

 

首先,我們要了解JS中算法的復(fù)雜度

標(biāo)記名稱   描述
O(1) 常數(shù) 不管有多少值,執(zhí)行的時(shí)間都是恒定的。一般表示簡(jiǎn)單值和存儲(chǔ)在變量中的值
O(log n) 對(duì)數(shù) 總的執(zhí)行時(shí)間和值的數(shù)量相關(guān),但是要完成算法并不一定要獲取每個(gè)值。例如:二分查詢
O(n)  線性 總執(zhí)行時(shí)間和值的數(shù)量直接相關(guān)。例如:遍歷某個(gè)數(shù)組中的所有元素
O(n^2) 平方 總執(zhí)行時(shí)間和值的數(shù)量有關(guān),每個(gè)值至少要獲取n次。例如:插入排序

 

常數(shù)值和訪問(wèn)數(shù)組元素操作都是O(1)操作;對(duì)象屬性查找操作是O(n)操作;

如let values =  [5, 10]; let sum = values[0] + values[1]屬于O(1)操作;let values = window.location.href屬于O(2)操作

 

①遇到有多次屬性查詢的場(chǎng)合,可以考慮是否能做優(yōu)化,例子如下

//這里總共做了6次屬性查詢,其中window.location.href.substring與window.location.href.indexOf分別為3次 let query = window.location.href.subsring(window.location.href.indexOf("?")) //改善, 第一次訪問(wèn)時(shí)復(fù)雜度會(huì)是O(n),但該版本只有4次屬性查詢,相對(duì)于原始版本節(jié)省了33% let url = window.location.href;
let query = url.substring(url.indexOf("?"));

 

②循環(huán)優(yōu)化,這里其實(shí)用后測(cè)試循環(huán)代替前測(cè)試循環(huán)會(huì)更好,不過(guò)本地不采用,例子如下

//原有復(fù)雜度為O(n) for (let i = 0; i < values.length; ++i){
  process(values[i]);  
} //更改后復(fù)雜度為O(1) for (let i = values.length - 1; i >= 0; --i){
  process(values[i])  
}

 

③最小化語(yǔ)句數(shù)相關(guān)

 

例如進(jìn)行多個(gè)聲明時(shí),我們可以進(jìn)行組合,例子如下

//多個(gè)聲明 let count = 5;
let color = "blue";
let values = [1, 2, 3]; //組合成一個(gè) let count = 5,
     color = ”blue",
     values = [1, 2, 3]

 

例如插入迭代值時(shí),例子如下

//修改前 let name = values[i];
i++; //修改后 let name = values[i++]

 

使用數(shù)組和對(duì)象字面量時(shí),例子如下

//修改前 let values = new Array();
values[0] = 123;
values[1] = 456;
values[2] = 789;

let person = new Object();
person.name = "Eric";
person.age = 20; //修改后 let values = [123, 456, 789]
let person = {
  name: "Eric",
  age:20,    
}

 

④創(chuàng)建DOM節(jié)點(diǎn)最好使用innerHTML方法,因?yàn)閕nnerHTML設(shè)置值時(shí),后臺(tái)會(huì)創(chuàng)建HTML解析器,然后使用內(nèi)部的DOM調(diào)用來(lái)創(chuàng)建DOM結(jié)構(gòu),而非基于JS的DOM調(diào)用。

調(diào)用一次innerHTML,就會(huì)進(jìn)行一次現(xiàn)場(chǎng)刷新,循環(huán)插入DOM結(jié)構(gòu)時(shí),應(yīng)注意盡量調(diào)用少次數(shù)的innerHTML,代碼如下

//錯(cuò)誤方法,做了很多次現(xiàn)場(chǎng)刷新 let list = document.getElementById("myList"),
    i; for (i = 0; i < 10; ++i){
  list.innerHTML = html+= "
  • Item " + i + "
  • " } //正確方法,盡管在字符串連接上有性能損失,但卻只做了一次現(xiàn)場(chǎng)刷新 let list = document.getElementById("myList"), html = "", i; for (i = 0; i < 10; ++i){ html += "
  • Item " + i + "
  • " } list.innerHTML = html

     

    ⑤其他如有多個(gè)if-else語(yǔ)句時(shí),應(yīng)盡可能轉(zhuǎn)為Switch語(yǔ)句;用appendChild()插入元素時(shí),應(yīng)采用自上而下插入;面向?qū)ο缶幊虝r(shí),應(yīng)合理釋放內(nèi)存,設(shè)object為null。



    上一篇:網(wǎng)頁(yè)前端HTML、JS、CSS應(yīng)用的主要知識(shí)點(diǎn)

    下一篇:JS頁(yè)面間數(shù)據(jù)傳遞的各種方法與不同頁(yè)面跳轉(zhuǎn)的傳值方法