摘要:是提出并積極開發的一種新的在線格式,旨在加快解析速度,同時保持原始的語義不變。它的實現方式是使用有效的二進制來表示代碼和數據結構,并且存儲和提供額外的信息來提前指導解析器工作。提升依賴于提升所有聲明變量函數類。
原文:Faster script loading with BinaryAST?JavaScirpt的冷啟動本文首發于公眾號:符合預期的CoyPan
web應用的表現,越來越受制于啟動時間。我們已經習慣于使用大量的JavaScript代碼來開發豐富的web交互體驗。從HTTPArchive上,我們可以看到,一個移動設備平均會加載350KB的JavaSript代碼,10%的頁面會加載超過1MB的JavaScipt代碼。復雜的交互會使得這個數字越來越高。
盡管有緩存的幫助,但是常見的站點都會頻繁的發布新代碼,導致冷啟動(首次加載)時間十分的重要。隨著瀏覽器將緩存按照域來劃分以防止跨站點泄露,冷啟動的重要性正在增加,即使是從CDN加載的常用資源來說也是如此,因為它們不再能夠安全地共享。
通常情況下,當我們談論冷啟動性能時,最常見的因素就是下載速度。然后,在現在的富交互頁面上,另外一個影響冷啟動的很重要因素是:JavaScipt的解析時間。咋看起來會有點讓人意外,但是是合理的:在開始執行代碼前,引擎不得不先解析下載的JavaScript,確保腳本沒有語法錯誤,然后將其編譯為基本的字節碼。隨著網絡變得越來越快,JavaScipt的解析和編譯可能會成為影響冷啟動的最主要因素。
設備能力(CPU或內存性能)是影響JavaScript解析時間和相應應用程序啟動時間變化的最重要因素。在現代桌面或高端移動設備上,一個1MB的javascript文件需要100毫秒的解析時間,但在普通手機上,解析時間可以超過一秒鐘。
關于在不同設備上javascript解析、編譯和執行的總體成本,這篇文章給出了詳細的介紹。以news.google.com為例,在Pixel 2上,解析、編譯、執行JS的總耗時為4s,而在一些低端的設備上,需要28s。
雖然引擎不斷提高原始解析性能,尤其是在過去的一年里,V8引擎的性能翻了一番,并且使更多的東西脫離了主線程,但解析器仍然需要做大量可能不必要的工作,這些工作會消耗內存、電池,并可能延遲有用資源的處理。
BinaryAST提案"BinaryAST"應運而生。BinaryAST是Mozilla提出并積極開發的一種新的在線javascript格式,旨在加快解析速度,同時保持原始javascript的語義不變。它的實現方式是:使用有效的二進制來表示代碼和數據結構,并且存儲和提供額外的信息來提前指導解析器工作。
之所以使用BinaryAST這個名字,是因為這種格式以AST的方式存儲JavaScript源碼,然后編碼到一個二進制文件中。該規范位于tc39.github.io/proposal-binary-ast,目前正由Mozilla、Facebook、Bloomberg和CloudFlare的工程師開發。
解析JavaScript對于要在瀏覽器中執行的常規JavaScript代碼,源代碼被解析為一個稱為AST的中間表示,它描述了代碼的語法結構。然后,可以將此AST編譯為字節代碼或本機代碼以供執行。
一段簡單的將兩個數相加的代碼,用AST表示為:
解析JavaScript不是一項簡單的任務;無論使用哪種優化,它仍然需要逐字符讀取整個文本文件,同時跟蹤額外的上下文進行語法分析。
BinaryAST的目標是通過在解析器需要的時間和地點提供額外的信息和上下文,來降低復雜性和瀏覽器解析器必須完成的總體工作量。
要執行以BinaryAST方式傳遞的JavaScript,所需要的唯一步驟是:
BinaryAST的另一個好處是它可以只解析啟動所需的關鍵代碼,完全跳過未使用的位。這可以顯著提高初始加載時間。
這篇文章將更加詳細地描述解析JavaScipt時遇到的挑戰,解釋我們是如何克服這些問題的,以及我們是如何在Worker中運行代碼解釋器的。
提升JavaScript依賴于提升所有聲明——變量、函數、類。提升是語言的一個屬性,它允許你在語法上使用之后,再去聲明變量,函數,類等。
讓我們來看下面這個例子:
function f() { return g(); } function g() { return 42; }
在這里,當解析器查看F的主體時,它還不知道G指的是什么——它可能是一個已經存在的全局函數或者在同一個文件中進一步聲明的某個函數——所以它無法最終解析原始函數并開始實際編譯。
BinaryAST通過存儲所有作用域信息并使其在實際表達式之前可用來解決這個問題。
用JSON表示初始的AST和增強的AST之前的區別,如下圖所示:
延遲解析現代引擎用來改進解析時間的一種常見技術是延遲解析。它利用了這樣一個事實:許多網站包含的javascript比實際需要的要多,特別是對于新的網站。
例如,從文本中解析數字、布爾值甚至字符串等低級類型需要額外的分析和計算。這是沒有必要的。您可以首先將它們存儲和讀取為本機二進制編碼值,然后直接在另一端讀取。
另一個問題是語法本身的歧義。這在ES5世界中已經是一個問題,但通常可以通過一些基于以前看到的標記的額外記錄來解決。然而,在ES6+中,有些東西可能一直模糊不清,直到它們被完全解析為止。
例如,一個標記序列如下:
(a, {b: c, d}, [e = 1])...
上述標記序列可以是一個用嵌套的對象和數組文本以及賦值來啟動帶括號的逗號表達式:
(a, {b: c, d}, [e = 1]); // 這是一個表達式
也可以是一個帶有嵌套對象和數組模式的箭頭表達式函數的參數列表和默認值:
(a, {b: c, d}, [e = 1]) => … // 這是一個參數列表
這兩種表示都是完全有效的,但語義完全不同,在看到最后一個標記之前,你無法知道要處理的是哪個。
為了解決這一問題,解析器通常要么回溯,這很容易以指數級的速度變慢,要么將內容解析為能夠同時保存表達式和模式的中間節點類型,并進行后續的轉換。后一種方法保留了線性性能,但使實現更加復雜,需要保留更多的狀態。
在BinaryAST格式下,這個問題不再存在。因為解析器在開始解析內容前就可以看到每個節點的類型。
展示實驗數據請記住,該提案處于非常早期的階段,當前的基準和演示不能代表最終結果。
如前所述,BinaryAST可以標記應該提前進行惰性分析的函數。通過在編碼器https://github.com/binast/binjs-ref/blob/b72aff7dac7c692a604e91f166028af957cdcda5/crates/binjs_es6/src/lazy.rs#L43中使用不同級別的惰性化,對一些流行的javascript庫運行測試時,我們發現了以下速度的提升。
在兩個解析器中都禁用了惰性解析之后,原始解析速度提高了3%到10%。
但是,通過設置為跳過最多嵌套3層的函數函數,我們可以看到解析時間在90%到97%之間的顯著改進。正如本文前面提到的,BinaryAST通過完全跳過標記的函數,使延遲解析基本上是無開銷的。
通過下面的包含1.2MB JavaScript的示例程序https://github.com/cloudflare...
https://serve-binjs.that-test...
我們得到了以下的初始腳本執行數據:
以下是一段視頻,它將讓您了解移動FireFox用戶所看到的改進(在本例中,顯示整個頁面啟動時間):
下一步是開始在現實網站上收集數據,同時改進底層格式。
如何在我的站點上測試BinaryAST?我們已經開源了Worker的源代碼,以便將其安裝到任何CloudFlare區域:
https://github.com/binast/bin...
目前需要注意的一件事是,即使結果存儲在緩存中,初始編碼仍然是一個昂貴的過程,并且可能很容易達到任何重要的javascript文件的CPU限制,并返回到未編碼的變量。我們正在努力改善這種情況,在接下來的日子里,將BinaryAST編碼器作為一個多帶帶的功能發布,并有更寬松的限制。
同時,如果你想在更大的腳本上使用BinaryAST,另一種選擇是使用https://github.com/binast/bin...,提前對javascript文件進行預編碼。然后,在瀏覽器支持和請求時,可以使用https://github.com/cloudflare...,來處理生成的BinaryAST文件。
在客戶端,您當前需要下載Firefox Nightly,轉到about:config并通過以下選項啟用無限制的binaryast支持。
現在,當打開一個安裝了Worker的網站時,Firefox會自動得到BinaryAST而不是javascript。
總結現代應用程序中的javascript數量正在給所有消費者帶來性能挑戰。引擎供應商正在嘗試各種不同的方法來改善這種情況——一些側重于原始解碼性能,一些側重于并行操作以減少總體延遲,一些致力于研究用于數據表示的新的優化格式,還有一些正在發明和改進用于網絡交付的協議。
不管是哪一個,我們都有一個共同的目標,那就是讓網絡變得更好、更快。
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/104268.html
摘要:每當解析器遇到腳本時,它必須停止并執行它,然后才能繼續解析。如果腳本動態地注入另一個腳本,解析器將被迫等待更長時間才能下載資源,這可能會導致一個或多個網絡往返并延遲首次渲染頁面的時間,導致頁面無法加載或花費的時間長于用戶放棄。 本文是技術圈 google 瀏覽器前端新特性播報的推送,歡迎大家加入 為什么要避免使用 document.write() 最近我們發現如果我們在頁面中使用了d...
摘要:下面針對對象時使用和時的個鮮為人知的技巧。對屬性進行排序有時性質并不按照我們需要的順序排列。若要將移到最后一個屬性,請從對象中解構。默認屬性默認屬性是僅當它們不包含在原始對象中時才設置的值。 showImg(https://segmentfault.com/img/remote/1460000018610267?w=800&h=530); [譯]使用 JavaScript 對象 Res...
我們在使用docker-compose的時候,應該都會有速度太慢的問題,今天我們就來了解下怎么加快docker-compose速度。解決辦法只有一個,就是換源。怎么換源呢?我們可以用下面這行程序換源一 換源執行sudochmod+x/usr/local/bin/docker-compose為了要防止報錯,我們要修改權限執行sudochmod+x/usr/local/bin/docker-compo...
摘要:如果使用傳統的海外服務器,可能經常會受到攻擊,而如果使用加速,那么中心服務器就只允許節點連接,這樣有效的提升了服務器的安全性及穩定性。首先,我們要了解一下什么是CDN加速,通俗點的理解就是說,將站點的內容緩存到最近的節點,這樣我們訪問站點時,可以直接從這個節點獲取需要的信息,這樣加快了我們的訪問速度,變向的節約我們的時間。那么海外服務器使用CDN加速有哪些好處呢?它可以有效提升海外服務器訪問...
閱讀 3309·2023-04-25 19:42
閱讀 1328·2021-11-23 10:11
閱讀 2251·2021-11-16 11:51
閱讀 1589·2019-08-30 15:54
閱讀 2035·2019-08-29 18:44
閱讀 1608·2019-08-23 18:24
閱讀 494·2019-08-23 17:52
閱讀 1763·2019-08-23 15:33