Prepack詳細介紹及微信小程序優化的新思路(lù) - 新聞資(zī)訊 - 雲南小程序開發|雲南軟件開發|雲南網站(zhàn)建設-西山區知普網絡科技工作室

159-8711-8523

雲南網建設/小程序開發/軟件開發

知識

不管是網站(zhàn),軟件還是小程序,都要直接或間接能為您産生價值,我們在追求其視覺表現的同時,更側重于功能的便捷,營銷的便利,運營的高效,讓網站(zhàn)成為營銷工具,讓軟件能切實提升企業(yè)内部管理水平和(hé)效率。優秀的程序為後期升級提供便捷的支持!

Prepack詳細介紹及微信小程序優化的新思路(lù)

發表時間:2021-4-30

發布人:葵宇科技

浏覽次數:49

前言

Prepack前幾個(gè)月(yuè)剛出來的時候已經得到了前端界的大範圍關(guān)注,而在不久之後又逐漸退出了人們的視線。此時這篇文(wén)章出來可(kě)能顯得有些滞後,個(gè)人還是比較看好它未來對于前端代碼預編譯優化所帶來的收益。所以再詳細地介紹一下(xià)Prepack和(hé)它給我帶來的思考。

在前端技術(shù)疊代更新速度較快、前端人力寶貴的情況下(xià),面對新技術(shù)的不斷湧現我們需要保持冷(lěng)靜和(hé)嚴謹的态度去接受這些新技術(shù),所以一般在一個(gè)新技術(shù)湧現時,我都會先弄清楚這幾個(gè)問(wèn)題再考慮是否要推動(dòng)和(hé)更疊現有的技術(shù)棧:

  • 是什麼?

  • 解決了什麼問(wèn)題?

  • 帶來了什麼新的問(wèn)題?

  • 新的問(wèn)題和(hé)解決的問(wèn)題在目前場景下(xià)權重是怎麼樣的?

  • 投入産出比如(rú)何?

帶着這幾個(gè)問(wèn)題進入正題。

一、什麼是Prepack

官網的第一句是:A tool for making JavaScript code run faster. —— 一個(gè)讓JavaScript代碼運行更快的工具。

實際上Prepack 就是一個(gè)部分求值器(qì)(Partial Evaluator),代碼打包編譯時提前将計算結果放到編譯後的代碼中(zhōng),從而去除冗餘的代碼(相對運行時來說,對應的代碼邏輯本身并不是冗餘的),而不是在代碼真正運行時才去求值。消除那些本可(kě)以在編譯階段完成的運行時計算,一定程度上減少(shǎo)了javascript資(zī)源包大小以及浏覽器(qì)運行js所耗費的時間。詳情移步prepack.io/

另外要說明的是,Prepack雖然能一定程度上減少(shǎo)代碼量的大小,但是Prepack開發團隊開發它的初衷并不是為了減少(shǎo)代碼包大小,主要還是減少(shǎo)運行時的時間消耗,代碼包的大小減少(shǎo)算是一個(gè)附加收益。

二、工作原理

根據官網列的幾個(gè)點依次進行詳細解釋。

  • Abstract Syntax Tree (AST) 抽象語法樹(shù) (粒度) Prepack在抽象語法樹(shù)的級别運行,使用Babel解析并生成JavaScript源代碼。 那什麼是“在抽象語法樹(shù)的級别運行”? 将一種結構化語言編譯成另一個(gè)結構化語言的代碼過程如(rú)下(xià):

1、Parse,将代碼解析成抽象語法樹(shù)(AST);

2、對抽象語法樹(shù)(AST)進行遍曆(traverse)和(hé)替換(replace) 生成新的 抽象語法樹(shù)(AST);

3、Generator—— 根據新的 AST 生成編譯後的代碼; “在抽象語法樹(shù)的級别運行” 說明了Prepack的編譯流程,也說明了編譯粒度。 比抽象語法樹(shù)粒度更細的還有一個(gè)分析樹(shù)。 例如(rú)以下(xià)一個(gè)3+4 例子(zǐ)的對比: 分析樹(shù):

抽象語法樹(shù):

概括來說,分析樹(shù)包含了記号序列和(hé)推導的各個(gè)步驟,拆分粒度更細;抽象語法樹(shù)則隻包含了關(guān)鍵的信息,不知道具體的文(wén)法和(hé)運算符細節。 在抽象語法樹(shù)的級别編譯,也就是說不用依賴于具體的文(wén)法,不依賴于語言的細節。也進一步說明,原code經過語法分析後總是構造出相同的抽象語法樹(shù),再通(tōng)過Prepack進行轉換處理成新的抽象語法樹(shù),Prepack不會對原有的代碼文(wén)法和(hé)處理邏輯帶來影響,對編譯器(qì)的接口的統一性也不會造成影響。 對編譯更多細節感興趣的可(kě)讀 兩周自制腳本語言 (圖靈程序設計叢書)

  • Concrete Execution 具體執行 Prepack的核心是一個(gè)JavaScript解釋器(qì),它與ECMAScript 5幾乎完全兼容,而且緊密地保持與 ECMAScript 2016語言規範 的一緻性,你(nǐ)可(kě)以将Prepack中(zhōng)的解釋器(qì)視為完全參照JavaScript實現的。

解釋器(qì)能夠跟蹤并撤銷包括所有對象Mutation在内的結果,從而能夠進行推測優化(Speculative Optimization)。

  • Symbolic Execution 符号執行 除了對具體值進行計算外,Prepack的解釋器(qì)還可(kě)以操作受環境相互作用影響的抽象值。例如(rú)Date.now可(kě)以返回一個(gè)抽象值,你(nǐ)可(kě)以通(tōng)過helper輔助函數(如(rú)__abstract())手動(dòng)注入抽象值。Prepack會跟蹤所有在抽象值上執行的操作,在遇到分支時,Prepack會執行并探索所有可(kě)能性。所以,Prepack實現了一套JavaScript的符号執行引擎。 以上是官網的翻譯,就是符号可(kě)以代表一個(gè)根據環境不同而可(kě)變的一個(gè)方法執行結果,例如(rú)以下(xià)例子(zǐ)中(zhōng)的_0就是這樣的一個(gè)抽象值,它無法提前計算,因為在不同的浏覽器(qì)或運行時機下(xià)結果是不同的。左邊編譯前代碼,x 存在if 判斷的分支情況,Prepack會彙總所有的分支情況進行優化編譯,如(rú)例子(zǐ)中(zhōng)将所有分支彙總(2個(gè)分支)替換成三目運算符表達。

  • Abstract Interpretation 抽象釋義 符号執行在遇到抽象值的分支時會分叉(fork),Prepack會在控制流合并點加入分歧執行(Diverged Execution)來實現抽象釋義的形式。連接變量和(hé)堆屬性可(kě)能會得到條件抽象值,Prepack會跟蹤有關(guān)抽象值和(hé)型域(Type Domain)的信息。 還是之前的例子(zǐ),就是抽象值“_0 ” 存在2個(gè)分支,Prepack底層會彙總分支情況,生成新的抽象語法樹(shù),在優化解析時(Generator)通(tōng)過連接變量和(hé)堆屬性,得到各分支下(xià)的抽象值“_0 ”可(kě)能的對應情況,并跟蹤相關(guān)情況的信息計算出結果形成新的代碼。

  • Heap Serialization堆序列化

這裡的堆序列化其實指的是當全局代碼返回,初始化階段結束時,也就是在generator 過程中(zhōng)Prepack 會捕獲最終的堆,按順序遍曆堆創建、鍊接堆中(zhōng)的可(kě)及對象。堆中(zhōng)的一些值可(kě)能是對抽象值進行計算的結果,Prepack 将會根據這些值生成執行計算的代碼,最終組成新的代碼。

總結一下(xià)Prepack的工作過程:

  1. 開發的代碼經過解析(Parse)形成抽象語法樹(shù)

  2. Transform時期預先計算出的可(kě)求的值,對存在受環境影響的抽象值進行抽象釋義,轉換成新的抽象樹(shù)

  3. Generate時期按順序遍曆堆進行符号執行和(hé)跟蹤有關(guān)抽象值和(hé)型域信息處理抽象值等,最終組成新的代碼。

三、示例

官網(prepack.io/)有舉代表性的例子(zǐ),這裡不再詳述。還可(kě)以通(tōng)過線上的Prepackprepack.io/repl.html将自己的代碼輸入動(dòng)态查看解析結果。

四、Prepack 引入會帶來的問(wèn)題

Prepack 帶來的優勢是把 js 的 AST 編譯到更加低級的語義,提前計算出值, 減少(shǎo) js 代碼在浏覽器(qì)端初始化運行消耗的時間,附帶收益是減少(shǎo)了代碼包的大小,還可(kě)以與Closure Compiler 配合進一步縮小代碼包.,但同時也帶來了新的問(wèn)題:

  • 沒有官方統一、成熟的方案支持打包集成到開發環境——需要開發者另辟蹊徑完成集成

  • 不能識别 document 和(hé) window,會識别為 undefined——浏覽器(qì)環境代碼利用Prepack存在較大局限性

  • 沒有完全支持浏覽器(qì)環境和(hé)node.js環境——node代碼不能全面接入Prepack

  • 生成的代碼沒有針對引擎做好優化——運行效率會存在變低的情況

  • 存在一些尚未解決的issues——會有更多的“坑”需要踩

五、Prepack 未來規劃

目前Prepack仍處于早期開發階段,尚未準備好在生産環境中(zhōng)使用,官方建議僅嘗試使用,并且歡迎提供反饋以幫助修複錯誤。

Prepack團隊對未來的規劃如(rú)下(xià):

短(duǎn)期

  • 穩定現有功能集,用于預優化(Prepack)React Native代碼包

  • 集成React Native工具鍊

  • 根據React Native所用模塊系統的假設來構建優化

中(zhōng)期

  • 進一步優化序列化(Serialization),包括:消除不暴露特性(identity)的對象;消除未使用的導出屬性,等等

  • 預優化每個(gè)函數、基本代碼塊、語句、表達式

  • 與ES6保持完全一緻

  • 支持廣泛的模塊系統

  • 假設ES6支持某些功能,延遲完成或直接忽略Polyfill應用

  • 進一步實現Web和(hé)Node.js環境中(zhōng)的兼容性目标

  • 深入集成JavaScript虛拟機,改進堆反序列化過程,包括 :暴露“對象懶初始化”的概念 - 以一種JavaScript無感知的方式,在首次使用對象時對其進行初始化;通(tōng)過專門的字節碼提高普通(tōng)對象創建的編碼效率;将代碼分為兩個(gè)階段:1) 非環境依賴階段,虛拟機可(kě)以安全地捕獲并恢複生成的堆;2)環境依賴階段,通(tōng)過從環境中(zhōng)獲得的值執行所有剩餘的計算過程來拼湊具體的堆,等等

  • 總結循環和(hé)遞歸

長期 - 利用Prepack作為一個(gè)平台

  • JavaScript Playground - 通(tōng)過調整JavaScript引擎體驗JavaScript特性,這些引擎由JavaScript所編寫,托管在浏覽器(qì)中(zhōng);你(nǐ)可(kě)以把它想象成一個(gè)“Babel虛拟機”,實現了不能被編譯的JavaScript新特性

  • 捉Bug - 發現異常崩潰、執行問(wèn)題……

  • 效果分析,例如(rú)檢測模塊工廠函數可(kě)能的副作用或強制純淨注釋

  • 類型分析

  • 信息流分析

  • 調用圖推理,允許内聯和(hé)代碼索引

  • 自動(dòng)測試生成,利用符号執行的特性與約束求解器(qì)(Constraint Solver)結合來計算執行不同執行路(lù)徑的輸入

  • 智能模糊(Smart Fuzzing)

  • JavaScript沙盒 - 以不可(kě)觀察的方式有效地測試JavaScript代碼

六、Prepack給微信小程序優化帶來的新思路(lù)

從以上Prepack帶來的優勢和(hé)問(wèn)題來看,在普遍的前端項目中(zhōng)使用的話投入較大于産出,目前必然是不适宜投入到項目中(zhōng)使用。

雖然目前Prepack尚未完善,但是開拓了一個(gè)新的js代碼優化方向。減少(shǎo) js 代碼在浏覽器(qì)端初始化運行消耗的時間,這對于提升用戶體驗來說也是很關(guān)鍵的點。例如(rú) app本身的啟動(dòng)一般也比較占用時間,所以一般app 都會有一個(gè)啟動(dòng)時的廣告頁或靜态介紹頁,借此消除啟動(dòng)時間較長給用戶帶來的不良體驗。 App可(kě)以用廣告頁和(hé)靜态介紹頁吸引用戶的注意力。

最近在做小程序相關(guān)的業(yè)務,微信小程序本質是app,在業(yè)務邏輯較重的小程序也同樣存在啟動(dòng)時間消耗帶來不良用戶體驗的問(wèn)題,但是卻不能以普通(tōng)app的解決方案來解決。因為微信本身比較注重用戶體驗,是一個(gè)擅長做減法且克制的産品,加入廣告和(hé)啟動(dòng)頁不僅會影響用戶體驗還破壞産品的“克制”性。 所以小程序的啟動(dòng)優化就需要新的解決思路(lù),而Prepack就剛好帶來了曙光。

微信小程序不存在 document 和(hé) window 對象,也非在node.js環境,不受它帶來的問(wèn)題所局限。可(kě)以通(tōng)過腳本或其他集成方式将Prepack加入到打包流程中(zhōng)完成優化,也可(kě)降級處理部分主要文(wén)件發揮他的作用。總之和(hé)微信小程序之間存在着可(kě)能性和(hé)可(kě)行性,後續會再出針對小程序和(hé)Prepack的實踐文(wén)章,感興趣的同學可(kě)待續。

以上純屬個(gè)人觀點,可(kě)能存在不足或錯誤之處,歡迎指正。

作者介紹:雪(xuě)婧,美團點評點餐團隊成員。

相關(guān)案例查看更多