高性能JavaScript

# JavaScript簡介
## 設計目標
JavaScript最初的目標是改善網頁的用戶體驗。JavaScript能代替服務器處理頁面中相似表單驗證的簡單任務,這樣節省了與服務器鏈接的大量時間
## JavaScript引擎
**瀏覽器使用JavaScript引擎解釋執行JavaScript代碼,做爲瀏覽器的組成部分之一,JavaScript引擎通常狀況下都是由瀏覽器開發商自行開發的,(如IE9的Chakra、Firefox的TraceMonkey、Chrome的V8),其中Chrome所使用的V8進行了極大的性能升級,做爲一款爲JavaScript打造的實時編譯引擎,它將JavaScript轉換爲機器碼來執行,極大地提高了JS的執行效率**
> **解釋器和編譯器的主要區別**
> * 編譯器沒法直接執行源代碼,而是先將源代碼編譯後生成中間碼或者是機器碼(典型的使用編譯器的語言有:C/C++/Java/C#);而解釋器則是直接逐行解析源代碼並執行(典型的使用解釋器的語言有JavaScript/html)
>* 編譯型語言的源代碼有錯誤的話沒法經過編譯,沒法生成可執行代碼,更沒法執行程序;而解釋型語言只有執行時纔會判斷是否出錯,即便一句出錯,也能夠繼續執行下一句
>* 編譯型的語言都爲強類型,類型檢驗較爲嚴格,而解釋型語言多爲弱類型,如js中的var a,a能夠爲字符串也能夠爲整形
>* 編譯型語言的執行效率要大大優於解釋型語言,由於編譯器在編譯過程當中會根據不一樣的平臺自動優化源代碼,而且一次編譯後生產的字節碼或者是機器碼能夠處處執行;而解釋型語言缺乏編譯優化的過程,而且逐行執行效率低下,每次執行都要從新解釋一遍,而且安全性較低
## JavaScript語言特性
* **單線程** 因爲Javascript做爲瀏覽器腳本語言,主要的用途是和用戶互動,以及操做DOM節點,這決定了它只能是單線程,不然會帶來很複雜的同步問題。因此,爲了不復雜性,從誕生起,Javascript就是單線程的,這已經成爲這門語言的核心特徵,未來也不會改變
* **任務隊列** 因爲JavaScript是單線程的,因此全部的任務須要排隊執行,可是若是前一個任務耗時很長(例如一些從網絡讀取數據的操做)的話,後一個任務就不得不等待執行。爲此JS將任務分爲兩種,一張是同步任務,另外一種是異步任務
>* **同步任務** 在主線程上排隊執行的任務,只有前一個任務執行完畢,才能執行後一個任務
>* **異步任務** 不進入主線程、而進入"任務隊列"(task queue)的任務,只有"任務隊列"通知主線程,某個異步任務能夠執行了,該任務纔會進入主線程執行
>* **同步任務和異步任務運行機制**
>>* 全部同步任務都在主線程上執行,造成一個執行棧(execution context stack)
>>* 主線程以外,還存在一個任務隊列(task queue),只要異步任務有了執行結果,就會在任務隊列中放置一個事件
>>* 一旦執行棧中的同步任務執行完畢,系統就會讀取任務隊列,看看裏面有哪些事件,那些對應的異步任務就結束等待狀態,進入執行棧開始執行
>>* 主線程不斷重複上面的步驟
* **事件和回調函數** 任務隊列是一個事件的隊列,IO設備完成一項任務,就在任務隊列中添加一個事件,表示相關的異步任務能夠進入執行棧了,主線程讀取任務隊列,就會讀取裏面有哪些事件。任務隊列中的事件,除了IO設備的事件之外,還包括一些用戶產生的事件(好比鼠標點擊,頁面滾動等),只要指定過回調函數,這些事件發生時就會進入任務隊列,等待主線程讀取所謂"回調函數"(callback),就是那些會被主線程掛起來的代碼。異步任務必須指定回調函數,當主線程開始執行異步任務,就是執行對應的回調函數。
"任務隊列"是一個先進先出的數據結構,排在前面的事件,優先被主線程讀取。主線程的讀取過程基本上是自動的,只要執行棧一清空,"任務隊列"上第一位的事件就自動進入主線程。可是,因爲存在後文提到的"定時器"功能,主線程首先要檢查一下執行時間,某些事件只有到了規定的時間,才能返回主線程。
* **Event Loop** 主線程從"任務隊列"中讀取事件,這個過程是循環不斷的,因此整個的這種運行機制又稱爲Event Loop(事件循環)
* **定時器** 除了放置異步任務的事件,"任務隊列"還能夠放置定時事件,即指定某些代碼在多少時間以後執行。這叫作"定時器"(timer)功能,也就是定時執行的代碼。定時器功能主要由setTimeout()和setInterval()這兩個函數來完成,它們的內部運行機制徹底同樣,區別在於前者指定的代碼是一次性執行,後者則爲反覆執行html

# JavaScript加載與執行
**JavaScript具備阻塞特性,因爲腳本執行過程當中可能會修改頁面內容,因此在遇到<script>標籤時,不管當前JavaScript代碼是內嵌的仍是包含在外鏈文件中,頁面的下載和渲染都必須等待腳本下載(外鏈腳本)和執行完畢**瀏覽器

## 腳本位置
HTML4規範指出<script>標籤能夠放在HTML文檔的<head>或<body>中,而且容許出現屢次。按照慣例,<head>中的<script>標籤用來加載外鏈JavaScript文件,挨着的<link>標籤用來加載外部CSS文件或者其餘頁面元信息,理論上說,把與樣式和行爲有關的腳本放在一塊兒,並先加載它們,有助於確保頁面渲染和交互的正確性
> 可是與此同時,在<head>中加載過多的外鏈JavaScript文件會帶來嚴重的性能問題,由於腳本會阻塞頁面渲染,因此直到全部的腳本下載並執行完成以後,頁面的渲染纔會繼續
> 目前多數瀏覽器都支持並行下載JavaScript文件,可是腳本阻塞問題仍然存在,頁面的渲染仍然須要等待全部JS代碼下載並執行完畢才能繼續
> 因爲腳本會阻塞頁面的渲染過程,所以仍是建議將全部<script>標籤放在<body>標籤的底部安全

## 組織腳本
**考慮到Http請求會帶來額外的性能開銷,所以下載單個100KB文件將比下載4個25KB的文件更快,有一些離線的打包工具或者在線服務能夠進行多個js文件的整合**服務器

相關文章
相關標籤/搜索