這段時間把《高性能JavaScript》書籍讀完,受益良多。在讀書的過程把重點精簡地提煉並結合本身的經驗記錄下來。也但願看完這篇文章可以給對JavaScript多瞭解一點點。javascript
瞭解: 當瀏覽器在執行JavaScript代碼時,是不可以同時作其餘事情。由於,絕大多數的瀏覽器使用單一線程來處理UI和JS。簡單地說,< script >標籤(內嵌或外鏈)的出現,頁面都會聽下來等待腳本下載並執行完成,由於腳本中可能會有修改頁面內容的操做。html
<html>
<head>
<script 1></script>
<script 2></script>
<script 3></script>
</head>
<body>
<div></div>
</body>
</html>
複製代碼
這樣的代碼存在十分嚴重的性能問題,整個解析的過程會卡頓在<script 1,2,3>的下載和執行的過程。而頁面內容遲遲不能呈如今用戶面前。 記住: 瀏覽器在解析n以前不會渲染頁面的任何部分,此時的表現爲空白。因此 < script > 放在頂部的作法很是不可取。java
js文件的下載執行流程:: 正則表達式
==那麼該如何去改進?== !!!並行下載js (後來的IE八、FireFox3.五、Safari四、Chrome2都容許並行下載JS文件了,也就是說你如今接觸到的大多瀏覽器的JS文件的下載都是並行的) 也就是::: JS文件是可以並行下載,可是頁面仍是會阻塞其餘資源下載(如圖片)而且會等待全部的JS文件下載完成並執行完成。 所以強烈推薦將全部的< script >標籤儘量的防盜標籤的底部,已儘可能減小對整個頁面的影響。考慮到Http請求會有額外的開銷,因此script標籤的個數不能過多。這個時候就要考慮將js文件進行合併已減小數量了。不過如今的不少打包工具都有這樣的功能,因此不用太過關注這個問題。算法
減小JS文件的大小及數量是優化的第一步(畢竟效果有限,由於js總會愈來愈多,愈來愈大)因此要考慮無阻塞的加載腳本方式。 而==無阻塞腳本的祕訣在於:頁面加載完成後再就在JS代碼(即在window.load()方法出發後再下載)==chrome
Defer屬性: HTML4爲< script >標籤訂義了defer擴展屬性,該屬性指明的JS文件不會修改DOM。但一開始只有IE四、FireFox3.5+支持;不事後來已經被全部的主流瀏覽器所支持。後來的H5中還添加了async擴展屬性。 區別編程
defer | async |
---|---|
並行下載JS | 並行下載JS |
等待頁面完成後執行(可是在load()方法調用以前) | 下載完成後執行 |
< script >標籤跟其餘的元素同樣,都能經過DOM操做。跨域
let scriptaEle = document.createElement('script');
scriptEle.type = 'text/script';
scriptEle.src = 'file1.js';
document.getElementByTagName('head')[0].appendChild(scriptEle);
複製代碼
==這個技術的重點在於:不管什麼時候啓動下載,文件的下載和執行的過程不會阻塞頁面的其餘過程。==數組
舒適提示:瀏覽器
有時該JS會被其餘的JS調用其中的方法,因此有時須要監聽JS下載的狀態。
全部狀態 | Value |
---|---|
uninitialized | 初始 |
loading | 開始下載 |
loaded | 下載完成 |
interactive | 完成但未可用 |
complete | 已準備就緒 |
==動態腳本憑藉其在跨瀏覽其兼容性和易用的優點,成爲最通用的無阻加載解決方案== 記住哈,想要優化JS的下載就採用動態腳本技術!!!
**瞭解:**另外一種無阻塞加載腳本方式:使用XMLHttpRequest技術獲取腳本並注入頁面(也就是用XHR網絡請求JS而後注入到頁面中) 例如:
let xhr = new XMLHttpRequest();
xhr.open('get','file.js',true);
xhr.onReadyStateChange = function () {
if(xhr.readyState === 4) {\
if(xhr.state >= 200 && xhr.status < 300 || ==304) {
//請求JS成功後,建立script標籤,將JS內容賦給script標籤;而後嵌入頁面
let script = document.createElement('script');
script.type = 'text/javascript';
script.text = xhr.responseText;
document.body.appendChild(script);
}
}
}
// 發起請求
xhr.send();
複製代碼
優勢:
向頁面中添加大量JS的推薦作法: 第一步:先添加動態加載全部的代碼 第二部:再加載剩餘JS代碼
有一些如LazyLoad的類庫能夠協助咱們快速的使用無阻塞加載JS
瞭解: 計算機科學中有一個經典的問題:經過改變數據的存取位置來得到最佳的讀寫性能。數據的存取位置關係到代碼執行過程當中的檢索速度。
js中有四種基本的數據存取位置: 字面量 : 字面量只表明自己,不存儲在特定位置。 : 有:字符串、數字、布爾、數組、函數、正則表達式、nullull、undefined 本地變量 : 開發人員使用var、let等定義的數據存儲單元 數組元素 : 存儲在JS數組對象內部,以數字爲索引 對象成員 : 存儲在JS對象內部,以字符串爲索引
**瞭解:**做用域是理解JS的關鍵,因此要重點的搞明白這一部分,從性能和功能的角度去思考。
須要瞭解以上問題的原理!
**瞭解:**JS函數是Function對象,和普通對象同樣擁有
可編程訪問的屬性
不可經過代碼訪問的內部屬性(而這其中有着很是重要的 ==[scope]== )
函數執行時建立一個爲執行環境的內部對象。函數每次執行的都會建立獨一無二的執行環境。當函數執行完畢,執行環境就會被銷燬。 每一個執行環境都有本身的做用域鏈,用於解析標誌符,在函數執行的過程當中,每遇到一個變量,都會經歷標誌符解析的過程以決定從哪裏獲取存儲數據。從頂層的「活動對象」做用域開始便利做用域鏈,知道找到爲止。 ==正式這個搜索過程,影響性能==一個標誌符所在的位置越深,他的讀寫速度越慢;因此全局變量訪問速度越慢(由於他老是在做用域鏈的末端) (這也是鏈式結構的特色) 綜上述:應該儘可能多的訪問局部變量。 經驗法則:若是某個跨做用域的值在函數中被引用一次以上,則把他存儲到局部變量
有兩個語句能夠在執行時,臨時改變做用域鏈。
第一個:with
· 第二個:try...catch
當進入catch時,會將異常對象推入做用域鏈的頂部
with、try...catch、eval()都被認爲是動態做用域鏈,動態做用域只存在於代碼執行過程當中,所以沒法經過靜態分析。
閉包:js最強的特性之一,函數訪問局部做用域以外的數據,使用閉包可能會致使性能問題,由於閉包函數阻礙了函數被正常回收,由於閉包有本身的做用域鏈,而且指向跟函數的做用域鏈同樣。 當閉包代碼執行時,會建立一個執行環境。
==閉包代碼中訪問的屬性的位置不在第一層,這就是使用閉包最需關注的性能點==;在頻繁訪問跨做用域的標誌符時,每次都有性能損失。(閉包同時關係到內存和執行速度)訪問成員比訪問字面量或變量要慢,爲了理解其中的緣由,有必要先了解JS的對象本質。
js的對象基於原型,他定義並實現了一個新建立的對象,所必須包含的成員列表。 對象經過一個內部屬性幫到他的原型,在firefox、safari、chrome瀏覽器中,這個屬性_proto_對開發者可見,而其餘瀏覽器確不容許腳本訪問此屬性。
不知不覺寫到這裏已經挺長的了,因此決定留到下一篇文章吧。 若是以爲對你有幫助,就點個喜歡吧!
==支持一下,無限的動力^_^==