老熟女激烈的高潮_日韩一级黄色录像_亚洲1区2区3区视频_精品少妇一区二区三区在线播放_国产欧美日产久久_午夜福利精品导航凹凸

重慶分公司,新征程啟航

為企業提供網站建設、域名注冊、服務器等服務

JavaScript的運行原理分析

今天小編給大家分享一下JavaScript的運行原理分析的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

創新互聯專業提供成都主機托管四川主機托管成都服務器托管四川服務器托管,支持按月付款!我們的承諾:貴族品質、平民價格,機房位于中國電信/網通/移動機房,成都服務器托管服務有保障!

掃描器

源代碼首先被分解成 chunk,每個 chunk 都可能采用不同的編碼,稍后會有一個字符流將所有 chunk 的編碼統一為 UTF-16。

在解析之前,掃描器會將 UTF-16 字符流分解成 token。token 是一段腳本中具有語義的最小單元。有不同類型的 token,包括空白符(用于 自動插入分號)、標識符、關鍵字以及代理對(僅當代理對無法被識別為其它東西時才會結合成標識符)。這些 token 之后被送往預解析器中,接著再送往解析器。

預解析器

解析器的工作量是最少的,只要足夠跳過傳入的源代碼并進行懶解析(而不是全解析)即可。預解析器確保輸入的源代碼包含有效語法,并生成足夠的信息來正確地編譯外部函數。這個準備好的函數稍后將按需編譯。

解析

解析器接收到掃描器生成的 token 后,現在需要生成一個供編譯器使用的中間表示。

首先我們來討論解析樹。解析樹,或者說 具體語法樹(CST)將源語法表示為一棵樹。每個葉子節點都是一個 token,而每個中間節點則表示一個語法規則。在英語里,語法規指的是名詞、主語等,而在編程里,語法規則指的是一個表達式。不過,解析樹的大小隨著程序大小會增長得很快。

相反,抽象語法樹 要更加簡潔。每個中間節點表示一個結構,比如一個減法運算(-),并且這棵樹并沒有展示源代碼的所有細節。例如,由括號定義的分組是蘊含在樹的結構中的。另外,標點符號、分隔符以及空白符都被省略了。你可以在 這里 了解更多 AST 和 CST 的區別。

接下來我們將重點放在 AST 上。以下面用 JavaScript 編寫的斐波那契程序為例:

function fib(n) {     if (n <= 1) return n;     return fib(n-1) + fib(n-2);     }

下面的 JSON 文件就是對應的抽象語法

了。這是用 AST Explorer 生成的。(如果你不熟悉這個,可以點擊這里來詳細了解 如何閱讀 JSON 格式的 AST)。

{    "type": "Program",    "start": 0,    "end": 73,    "body": [      {        "type": "FunctionDeclaration",        "start": 0,        "end": 73,        "id": {          "type": "Identifier",          "start": 9,          "end": 12,          "name": "fib"        },        "expression": false,        "generator": false,        "async": false,        "params": [          {            "type": "Identifier",            "start": 13,            "end": 14,            "name": "n"          }        ],        "body": {          "type": "BlockStatement",          "start": 16,          "end": 73,          "body": [            {              "type": "IfStatement",              "start": 20,              "end": 41,              "test": {                "type": "BinaryExpression",                "start": 24,                "end": 30,                "left": {                  "type": "Identifier",                  "start": 24,                  "end": 25,                  "name": "n"                },                "operator": "<=",                "right": {                  "type": "Literal",                  "start": 29,                  "end": 30,                  "value": 1,                  "raw": "1"                }              },              "consequent": {                "type": "ReturnStatement",                "start": 32,                "end": 41,                "argument": {                  "type": "Identifier",                  "start": 39,                  "end": 40,                  "name": "n"                }              },              "alternate": null            },            {              "type": "ReturnStatement",              "start": 44,              "end": 71,              "argument": {                "type": "BinaryExpression",                "start": 51,                "end": 70,                "left": {                  "type": "CallExpression",                  "start": 51,                  "end": 59,                  "callee": {                    "type": "Identifier",                    "start": 51,                    "end": 54,                    "name": "fib"                  },                  "arguments": [                    {                      "type": "BinaryExpression",                      "start": 55,                      "end": 58,                      "left": {                        "type": "Identifier",                        "start": 55,                        "end": 56,                        "name": "n"                      },                      "operator": "-",                      "right": {                        "type": "Literal",                        "start": 57,                        "end": 58,                        "value": 1,                        "raw": "1"                      }                    }                  ]                },                "operator": "+",                "right": {                  "type": "CallExpression",                  "start": 62,                  "end": 70,                  "callee": {                    "type": "Identifier",                    "start": 62,                    "end": 65,                    "name": "fib"                  },                  "arguments": [                    {                      "type": "BinaryExpression",                      "start": 66,                      "end": 69,                      "left": {                        "type": "Identifier",                        "start": 66,                        "end": 67,                        "name": "n"                      },                      "operator": "-",                      "right": {                        "type": "Literal",                        "start": 68,                        "end": 69,                        "value": 2,                        "raw": "2"                      }                    }                  ]                }              }            }          ]        }      }    ],    "sourceType": "module"  }  (來源:GitHub)

上面代碼的要點是,每個非葉子節點都是一個運算符,而每個葉子節點都是操作數。這棵語法樹稍后將作為輸入傳給 JavaScript 接著要執行的兩個階段。

三個技巧優化你的 JavaScript

下面羅列的技巧清單中,我會省略那些已經廣泛使用的技巧,例如縮減代碼來最大化信息密度,從而使掃描器更具有時效性。另外,我也會跳過那些適用范圍很小的建議,例如避免使用非 ASCII 字符。

提高解析性能的方法數不勝數,讓我們著眼于其中適用范圍最廣泛的方法吧。

1.盡可能遵從工作線程

主線程被阻塞會導致用戶交互的延遲,所以應該盡可能減少主線程上的工作。關鍵就是要識別并避免會導致主線程中某些任務長時間運行的解析行為。

這種啟發式超出了解析器的優化范圍。例如,用戶控制的 JavaScript 代碼段可以使用 web workers 達到相同的效果。你可以閱讀 實時處理應用 和 在 angular 中使用 web workers 來了解更多信息。

避免使用大量的內聯腳本

內聯腳本是在主線程中處理的,根據之前的說法,應該盡量避免這樣做。事實上,除了異步和延遲加載之外,任何 JavaScript 的加載都會阻塞主線程。

避免嵌套外層函數

懶編譯也是發生在主線程上的。不過,如果處理得當的話,懶解析可以加快啟動速度。想要強制進行全解析的話,可以使用諸如 optimize.js(已經不維護)這樣的工具來決定進行全解析或者懶解析。

分解超過 100kB 的文件

將大文件分解成小文件以最大化并行腳本的加載速度。“2019 年 JavaScript 的性能開銷”一文比較了 Facebook 網站和 Reddit 網站的文件大小。前者通過在 300 多個請求中拆分大約 6MB 的 JavaScript ,成功將解析和編譯工作在主線程上的占比控制到 30%;相反,Reddit 的主線程上進行解析和編譯工作的達到了將近 80%。

2. 使用 JSON 而不是對象字面量 —— 偶爾

在 JavaScript 中,解析 JSON 比解析對象字面量來得更加高效。 parsing benchmark 已經證實了這一點。在不同的主流 JavaScript 執行引擎中分別解析一個 8MB 大小的文件,前者的解析速度最高可以提升 2 倍。

2019 年谷歌開發者大會 也討論過 JSON 解析如此高效的兩個原因:

  1.  JSON 是單字符串 token,而對象字面量可能包含大量的嵌套對象和 token;

  2.  語法對上下文是敏感的。解析器逐字檢查源代碼,并不知道某個代碼塊是一個對象字面量。而左大括號不僅可以表明它是一個對象字面量,還可以表明它是一個解構對象或者箭頭函數。

不過,值得注意的是,JSON.parse 同樣會阻塞主線程。對于超過 1MB 的文件,可以使用 FlatBuffers 提高解析效率。

3. 最大化代碼緩存

最后,你可以通過完全規避解析來提高解析效率。對于服務端編譯來說, WebAssembly (WASM) 是個不錯的選擇。然而,它沒辦法替代 JavaScript。對于 JS,更合適的方法是最大化代碼緩存。

值得注意的是,緩存并不是任何時候都生效的。在執行結束之前編譯的任何代碼都會被緩存 —— 這意味著處理器、監聽器等不會被緩存。為了最大化代碼緩存,你必須最大化執行結束之前編譯的代碼數量。其中一個方法就是使用立即執行函數(IIFE)啟發式:解析器會通過啟發式的方法標識出這些 IIFE 函數,它們會在稍后立即被編譯。因此,使用啟發式的方法可以確保一個函數在腳本執行結束之前被編譯。

此外,緩存是基于單個腳本執行的。這意味著更新腳本將會使緩存失效。V8 團隊建議可以分割腳本或者合并腳本,從而實現代碼緩存。但是,這兩個建議是互相矛盾的。你可以閱讀“JavaScript 開發中的代碼緩存”來了解更多代碼緩存相關的信息。

以上就是“JavaScript的運行原理分析”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注創新互聯行業資訊頻道。


分享標題:JavaScript的運行原理分析
文章出自:http://www.xueling.net.cn/article/pdsghg.html

其他資訊

在線咨詢
服務熱線
服務熱線:028-86922220
TOP
主站蜘蛛池模板: 日日干视频 | 一级特黄大片在线观看 | 黄色网址在线视频 | 久久久综合网 | 四虎永久成年免费影院 | 九色视频网站入口 | 国产国拍亚洲精品av在线 | 亚洲A∨国产AV综合AV | 黑人40厘米全部进去A片 | 野花香社区在线视频观看播放 | 日韩一区精品视频一区二区 | 免费精品国自产拍在线观看 | 久久国产精品视频一区 | 国产高清一级 | WWW性久久久COM | av免费在线网址 | 韩日在线观看视频 | 亚洲九草 | 永久免费无代码开发平台网站 | 91污污| japan21xxxxhd日本妞| 饥渴少妇浪潮AV麻豆传煤 | 日韩人妻无码精品无码中文字幕 | 亚洲国产精品久久人人爱蜜臀 | 亚洲欧美日本久久综合网站 | 日日撸夜夜撸 | 国产精品久久久久久久免费大片 | 国产高清一二区 | 又爽又黄又爽又刺激的视频 | 激情综合五月 | 欧美videosfreeⅹ尸交 | 高清国产下药迷倒白嫩美女99 | 天堂国产| 爱情岛论坛自拍亚洲品质极速福利 | 99re中文在线视频 | av高清在线观看 | 少妇裸体淫交视频免费看 | 色先锋资源在线播放av | 在线视频精品一区 | 99三级视频 | 91久久精品日日躁夜夜躁国产 |