第九章 構(gòu)建并部署高性能JavaScript應(yīng)用
1 合并多個(gè)JS文件示绊,減少HTTP請(qǐng)求數(shù)
2 預(yù)處理JS文件斤儿,雖不會(huì)提高性能,但允許你做其他事情贷岸,如有條件的插入測(cè)試代碼來(lái)衡 量應(yīng)用程序的性能
3 壓縮JS和CSS
4 只要是能在構(gòu)建時(shí)完成的工作就不要留到運(yùn)行時(shí)去做跃闹,如合并嵌削、壓縮、預(yù)處理等
5 JS的壓縮有很多工具望艺,如gzip (適合純文本苛秕,有圖片不行)、YUI Compressor和Packer找默,最佳實(shí)踐是使用YUI Compressor合并再使用gzip壓縮艇劫,Packer可用于網(wǎng)速較慢或不支持Gzip的情況
6 緩存JS文件。服務(wù)器可通過(guò)“Expire HTTP響應(yīng)頭”來(lái)告訴客戶(hù)端一個(gè)資源應(yīng)當(dāng)緩存多長(zhǎng)時(shí)間惩激,可通過(guò)設(shè)置緩存時(shí)間為一年將緩存時(shí)間設(shè)為永不過(guò)期店煞,然而有的瀏覽器可能會(huì)有緩存限制,此時(shí)可考慮采用客戶(hù)端存儲(chǔ)機(jī)制风钻,如cookies顷蟀,localstorage及sessionstorage,不過(guò)此時(shí)JS代碼必須自行控制到期時(shí)間骡技,另外還可以使用HTML5離線(xiàn)應(yīng)用緩存技術(shù)鸣个,缺點(diǎn)是要確保用戶(hù)下載的都是最新的內(nèi)容
7 使用內(nèi)容分發(fā)網(wǎng)絡(luò)CDN,可增強(qiáng)WEB應(yīng)用的可靠性布朦,可擴(kuò)展性還能提高性能囤萤。通過(guò)向地理位置最近的用戶(hù)傳輸內(nèi)容,CDN能極大減少網(wǎng)絡(luò)延時(shí)
第八章 編程實(shí)踐
1 避免雙重求值是趴。JS允許你在程序中提取一個(gè)包含代碼的字符串涛舍,然后動(dòng)態(tài)執(zhí)行它。有四種標(biāo)準(zhǔn)方法可以實(shí)現(xiàn):eval右遭,Function()構(gòu)造函數(shù)做盅,setTimeout()和setInterval()缤削,每個(gè)方法都允許你傳入一個(gè)JS代碼字符串并執(zhí)行它窘哈,代碼字符串指?jìng)魅氲氖亲址珗?zhí)行時(shí)用的是該字符串所對(duì)應(yīng)的值亭敢。這些方法都會(huì)導(dǎo)致雙重求值滚婉,因?yàn)槊看握{(diào)用這些函數(shù)時(shí)都要?jiǎng)?chuàng)建一個(gè)新的解釋器/編譯器實(shí)例,從而導(dǎo)致代碼執(zhí)行速度變慢帅刀。故沒(méi)必要使用eval()和Function時(shí)就避免使用他們让腹。至于setTimeout()和setInterval()远剩,建議傳入函數(shù)而不是字符串來(lái)作為第一個(gè)參數(shù)
2 使用Object/Array直接量
Var Myobject=new『稀Object()瓜晤;
Myobject.name="nick";
Var「鼓伞Myobject={
name:"nick"
}
推薦使用第二種方式:1 速度快 ×÷印2 省空間
3 不做重復(fù)工作
1 延遲加載(在每個(gè)分支語(yǔ)句里覆蓋函數(shù)即可實(shí)現(xiàn))
2 條件預(yù)加載(在腳本加載時(shí)就檢測(cè),而不是加載后)
4 使用速度快的部分
1 進(jìn)行數(shù)學(xué)運(yùn)算時(shí)使用位運(yùn)算或使用Math對(duì)象的API
2 盡量使用原生JS方法嘲恍,如DOM操作查找節(jié)點(diǎn)時(shí)可用querySelecto r()方法
第七章 AJAX
1 數(shù)據(jù)傳輸--請(qǐng)求數(shù)據(jù)技術(shù)
A .XHR
當(dāng)使用get方式時(shí)足画,請(qǐng)求的資源會(huì)被緩存,只有當(dāng)url加上參數(shù)的長(zhǎng)度接近或超過(guò)2048個(gè)字符時(shí)才應(yīng)該用post佃牛。不能跨域請(qǐng)求數(shù)據(jù)
B. 動(dòng)態(tài)腳本注入
可跨域請(qǐng)求數(shù)據(jù)淹辞,只需用JS動(dòng)態(tài)創(chuàng)建一個(gè)腳本標(biāo)簽,然后設(shè)置他的src屬性為不同域的URL即可俘侠,不能設(shè)置請(qǐng)求的頭信息象缀,只能使用get方式,也不能訪問(wèn)請(qǐng)求的頭信息爷速,不能把響應(yīng)消息作為字符串處理攻冷。響應(yīng)消息是作為腳本標(biāo)簽的源碼,故必須是可執(zhí)行的JS代碼遍希,不能使用純XML等曼,純Json或其他任何格式的數(shù)據(jù),無(wú)論哪種格式凿蒜,都必須封裝在一個(gè)回調(diào)函數(shù)中禁谦。
C .MXHR
該技術(shù)允許客戶(hù)端只用一個(gè)HTTP請(qǐng)求就可以從服務(wù)器想客戶(hù)端傳送多個(gè)資源。他通過(guò)在服務(wù)器端將資源打包成一個(gè)雙方約定的字符串分割的長(zhǎng)字符串并發(fā)送到客戶(hù)端废封,然后用JS代碼處理這個(gè)長(zhǎng)字符串州泊,并根據(jù)mime-type類(lèi)型和傳入的其他頭信息解析出每個(gè)資源。該技術(shù)最大的缺點(diǎn)是不能緩存數(shù)據(jù)
2 數(shù)據(jù)傳輸--發(fā)送數(shù)據(jù)技術(shù)
A .XHR
B. Beacons(圖片信標(biāo))
類(lèi)似于動(dòng)態(tài)腳本注入漂洋,使用JS創(chuàng)建一個(gè)新的Image對(duì)象遥皂,并把src屬性設(shè)置為服務(wù)器上腳本的URL,注意沒(méi)有創(chuàng)建img元素或把他插入DOM刽漂,服務(wù)器端無(wú)需向客戶(hù)端返回回饋信息演训,這是給服務(wù)器回傳信息的最有效的方式。缺點(diǎn):不能使用post贝咙,接收到的響應(yīng)類(lèi)型是有限的样悟。適用于只關(guān)心發(fā)送數(shù)據(jù)到服務(wù)器,不關(guān)心返回?cái)?shù)據(jù)
3 數(shù)據(jù)格式
A XML
Xpath
B JSON
XHR+JSON,JSON數(shù)據(jù)被當(dāng)成字符串返回窟她,然后使用eval()轉(zhuǎn)換為原生對(duì)象
動(dòng)態(tài)腳本注入+JSON-P陈症,JSON數(shù)據(jù)被當(dāng)成JS文件并作為原生代碼執(zhí)行
C HTML
D 自定義格式
速度最快的是使用數(shù)組形式的JSON-P
4 AJAX性能指南之緩存數(shù)據(jù)
1 設(shè)置HTTP頭信息
若希望AJAX響應(yīng)被瀏覽器緩存,那么必須使用get方式發(fā)出請(qǐng)求震糖,并在服務(wù)器端設(shè)置HTTP頭信息中的expire時(shí)間
2 本地?cái)?shù)據(jù)存儲(chǔ)
除了依賴(lài)瀏覽器處理緩存外录肯,還可以使用手工方式實(shí)現(xiàn),即直接把服務(wù)器接收到的數(shù)據(jù)儲(chǔ)存起來(lái)吊说,把響應(yīng)文本保存到一個(gè)對(duì)象中嘁信,以URL為鍵值作為索引
var localCathe={};
function xhrRequest(url,callback){
//檢查此URL的本地緩存
if(localCathe[url]){
callback.success(localCathe[url]);
return;
}
//此URL緩存不存在
var req=creatXhrObject();
req.onerror=function(){
callback.error();
};
req.onreadystatechange=function(){
if(req.readyState==4){
if(req.responseText===''||req.status=='404'){
callback.error();
return;
}
//存儲(chǔ)相應(yīng)文本到本地緩存
localCathe[url]=req.responseText;
callback.success(req.responseText);
}
};
req.open("GET",url,true);
req.send(null);
}
第五章 字符串與正則表達(dá)式
1 字符串連接
str+=s1+s2與str=str+s1+s2的區(qū)別:
前者經(jīng)歷四個(gè)步驟:1 在內(nèi)存中創(chuàng)建一個(gè)臨時(shí)字符串2連接s1和s2后賦給該變量3臨時(shí)字 符串與str連接4 結(jié)果賦給str
后者經(jīng)歷兩個(gè)步驟:1將s1拷貝到str末尾 2將s2拷貝到str+s1的末尾
后者避免了使用臨時(shí)變量,性能會(huì)有提升
2 數(shù)組項(xiàng)連接
Array.prototype.join方法將數(shù)組的所有元素合并成一個(gè)字符串
String.prototype.concat方法通常比+疏叨,+=操作符慢
第四章 算法與流程控制
1 JS中共有四種循環(huán)潘靖,for while do-while for-in,其中for-in用于遍歷對(duì)象中的屬性,
2 改善循環(huán)性能的最佳方式是減少每次迭代的運(yùn)算量(最小化屬性查找和倒敘循環(huán)法)和減 少循環(huán)迭代次數(shù)(達(dá)夫設(shè)備法)
3 通常蚤蔓,switch總是比if-else快卦溢,但并不總是最佳解決方案
4 判斷條件較多時(shí),使用查找表比if-else和switch更快
5 瀏覽器調(diào)用棧大小限制了遞歸算法在JS中的應(yīng)用秀又,棧溢出錯(cuò)誤會(huì)導(dǎo)致其他代碼中斷執(zhí)行单寂, 若遇到這種情況,可將方法改為迭代算法或使用Memoization(使用緩存技術(shù))來(lái)避免重 復(fù)計(jì)算
第三章 DOM編程
1 減少訪問(wèn)DOM的次數(shù)吐辙,把運(yùn)算盡量留在ECMAScript這邊
2 關(guān)于修改頁(yè)面區(qū)域的最佳方案:對(duì)于舊版本的瀏覽器宣决,建議使用innerHTML;對(duì)于新版本的瀏覽器昏苏,建議使用DOM方法(creatElement等方法)
3 使用DOM方法更新頁(yè)面內(nèi)容的另一個(gè)途徑是克隆已有元素尊沸,而不是創(chuàng)建新元素,即使用cloneNode方法代替creatElement方法贤惯,在大多數(shù)瀏覽器中洼专,克隆更有效率
4 HTML集合是包含了DOM節(jié)點(diǎn)引用的類(lèi)數(shù)組對(duì)象,返回該集合的方法有:getElementsByName() getElementsByClassName() getElementsByTagName() 返回該集合的屬性有:document.images document.links document.forms document.forms[0].elements
類(lèi)數(shù)組對(duì)象沒(méi)有push和slice等數(shù)組方法孵构,但可以通過(guò)下標(biāo)訪問(wèn)列表中的元素屁商,也提供了length屬性,但HTML集合處于一種實(shí)時(shí)狀態(tài)颈墅,即當(dāng)?shù)讓游臋n對(duì)象更新時(shí)他也會(huì)自動(dòng)更新蜡镶。
Array.prototype.slice.call(HTML集合)可將集合轉(zhuǎn)化為JS數(shù)組
5 DOM遍歷 1 當(dāng)你需要從某一個(gè)DOM元素開(kāi)始操作周?chē)脑鼗蜻f歸查找所有子節(jié)點(diǎn),你可以使用childNodes或nextSibling,在IE中nextSilbing比childNodes快恤筛,其他瀏覽器中差不多 2 使用children代替childNodes 3 使用querySelector和querySelectorAll代替getElementById等方法官还,用之前要檢查瀏覽器是否支持這兩個(gè)函數(shù)
6 重繪與重排
瀏覽器下載完頁(yè)面中的所有組件---HTML標(biāo)記、JS叹俏、CSS妻枕、圖片之后會(huì)解析并生成兩個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu):DOM樹(shù)和渲染樹(shù)僻族。當(dāng)DOM的變化影響了元素的集合屬性(寬和高)粘驰,會(huì)引發(fā)重排操作屡谐,完成重排后再進(jìn)行重繪操作。重排和重繪都是代價(jià)昂貴的操作蝌数,應(yīng)當(dāng)避免愕掏。下列情況會(huì)導(dǎo)致重排:(當(dāng)滾動(dòng)條出現(xiàn)時(shí)會(huì)導(dǎo)致整個(gè)頁(yè)面的重排)
1 添加或者刪除可見(jiàn)的DOM元素
2 元素位置改變
3 元素尺寸改變
4 元素內(nèi)容改變(例如:一個(gè)文本被另一個(gè)不同尺寸的圖片替代)
5 頁(yè)面渲染初始化(這個(gè)無(wú)法避免)
6 瀏覽器窗口尺寸改變
注意:1 盡量不要在布局信息改變時(shí)做查詢(xún),這會(huì)導(dǎo)致強(qiáng)制刷新隊(duì)列并要求計(jì)劃任務(wù)立刻執(zhí) 行(多數(shù)瀏覽器通過(guò)隊(duì)列化修改并批量執(zhí)行來(lái)優(yōu)化重排過(guò)程)
1 offsetTop, offsetLeft, offsetWidth, offsetHeight
2 scrollTop, scrollLeft, scrollWidth, scrollHeight
3 clientTop, clientLeft, clientWidth, clientHeight
4 getComputedStyle() (currentStyle in IE)
[圖片上傳失敗...(image-e70534-1519915919725)]
2 最小化重排和重繪(將多個(gè)操作合并為一個(gè)顶伞,從而只會(huì)修改DOM一次饵撑,如cssText 屬性)
3 批量修改DOM:1 是元素脫離文檔流2對(duì)其應(yīng)用多重改變3把元素帶回文檔中
讓元素脫離文檔流的方法:1隱藏元素2使用文檔片段(在當(dāng)前DOM之外構(gòu)建一 個(gè)子樹(shù),在拷貝回文檔)3 將原始元素拷貝到一個(gè)脫離文檔的節(jié)點(diǎn)中唆貌,修改副本再 替換
4 動(dòng)畫(huà)中使用絕對(duì)定位滑潘,使用拖放代理,使用事件委托減少事件處理器的數(shù)量
第二章 數(shù)據(jù)訪問(wèn)
1 JS中有四種基本的數(shù)據(jù)存取位置:直接量(如字符串锨咙,數(shù)字语卤,布爾,對(duì)象等)酪刀,變量(用var定義)粹舵,數(shù)組元素,對(duì)象成員骂倘,一般前兩者速度快于后兩者
2 通常來(lái)說(shuō)眼滤,可以通過(guò)把常用的對(duì)象成員、數(shù)組元素历涝、跨域變量保存在局部變量中來(lái)改善JS性能诅需,因?yàn)榫植孔兞吭L問(wèn)速度最快(緩存全局變量)
3 對(duì)象的方法不要賦值給局部變量,把一個(gè)方法保存在局部變量會(huì)導(dǎo)致this綁定到window
第一章 加載與執(zhí)行
1 JS代碼應(yīng)該放在</body>標(biāo)簽之前
2 減少<script>標(biāo)簽(每下載一個(gè)js文件都會(huì)執(zhí)行荧库,從而導(dǎo)致延時(shí)诱担。可通過(guò)合并JS文件達(dá)到)
3 不要把內(nèi)嵌腳本緊跟在<link>標(biāo)簽之后(會(huì)導(dǎo)致頁(yè)面阻塞去等待樣式表下載)
4 無(wú)阻塞腳本技術(shù):1 使用defer屬性电爹,只有IE4+和Firefox3.5+支持蔫仙。帶有defer屬性的script 元素在DOM加載之前不會(huì)執(zhí)行,而是在onload事件處理器執(zhí)行之前被調(diào)用
2 動(dòng)態(tài)腳本元素
function loadScript (url,callback) {
var script=document.createElement("script");
script.type="text/javascript";
if (script.readyState) {//針對(duì)IE
script.onreadystatechange=function () {
if (script.readyState=="loaded"||script.readyState=="complete") {
script.onreadystatechange=null;
callback();
}
};
}else{//針對(duì)其他瀏覽器
script.onload=function(){
callback();
};
}
script.src=url;
document.getElementsByTagName("head")[0].appendChild(script);
}
3 XMLHttpRequest腳本注入
var xhr=new XMLHttpRequest();
xhr.open("get",file1.js,true);
xhr.onreadystatechange=function(){
if(xhr.readyState==4){
if(xhr.status>=200&&xhr.status<300||xhr.status==304){
var script=document.creatElement("script");
script.type="text/javascript";
script.text=xhr.responseText;
document.body.appendChild(script);
}
}
};
xhr.send(null);
優(yōu)點(diǎn):下載后不會(huì)自動(dòng)執(zhí)行丐箩;適用于所有主流瀏覽器
缺點(diǎn):請(qǐng)求的JS文件必須與所請(qǐng)求的頁(yè)面同域摇邦,即不能從CDN下載