Taro 是一個(gè)開放式跨端跨框架解決方案唱捣,支持使用 React/Vue/Nerv 等框架來開發(fā)微信/京東/百度/支付寶/字節(jié)跳動(dòng)/ QQ 小程序/H5 等應(yīng)用郁稍。
本篇文章重點(diǎn)關(guān)注基于Taro Next(React)的微信小程序渲染,主要將從以下幾個(gè)方面進(jìn)行:
- 瀏覽器渲染流程
- React 渲染流程
- 微信小程序渲染流程
- 基于Taro Next(React)的微信小程序渲染流程
- 基于Taro Next(React)的微信小程序渲染問題和解決方案
瀏覽器渲染流程
用戶通過在地址欄輸入一個(gè)網(wǎng)站的URL后穿肄,內(nèi)容顯示到瀏覽器的完整過程
- 瀏覽器查看是否需要redirect, 如果需要闺阱,則redirect到對應(yīng)url
- 查看是否命中緩存焚辅,如果有直接到7己儒,如果沒有繼續(xù)3
- 解析域名,進(jìn)行DNS查找
- 創(chuàng)建http(s)連接
- 開始發(fā)送請求
- 接收服務(wù)端響應(yīng)
- 解析處理HTML標(biāo)記并構(gòu)造DOM樹
- 預(yù)加載掃描儀將解析可用的內(nèi)容并請求高優(yōu)先級資源巾腕,如CSS面睛、JavaScript和web字體
- 解析處理CSS并構(gòu)建CSSOM樹
- 下載其他資源。當(dāng)CSS被解析并創(chuàng)建CSSOM時(shí)尊搬,其他資源叁鉴,包括JavaScript文件正在下載。JavaScript被解釋毁嗦、編譯亲茅、解析和執(zhí)行。
- CSSOM樹和DOM樹組合 創(chuàng)建一個(gè)Render樹狗准。Render樹保存所有具有內(nèi)容和計(jì)算樣式的可見節(jié)點(diǎn)
- 在Render樹上運(yùn)行布局以計(jì)算每個(gè)節(jié)點(diǎn)的幾何體
- 將各個(gè)節(jié)點(diǎn)繪制到屏幕上克锣,在繪制或光柵化階段,瀏覽器將在布局階段計(jì)算的每個(gè)框轉(zhuǎn)換為屏幕上的實(shí)際像素
- 合成文檔中不同的層腔长,以確保相互重疊層以正確的順序繪制到屏幕上袭祟,并正確顯示內(nèi)容
React 渲染流程
JSX 會(huì)被編譯轉(zhuǎn)換成 React.createElement 函數(shù)的調(diào)用,其返回值就是 VNode(JS對象)捞附,虛擬DOM節(jié)點(diǎn)的描述對象巾乳。
- 在首次渲染時(shí),所有組件會(huì)創(chuàng)建對應(yīng)的VNode
- React 將 React.render 接收到的 VNode 轉(zhuǎn)化虛擬 DOM 樹
- 根據(jù)虛擬 DOM 樹的層級關(guān)系鸟召,構(gòu)建生成出 DOM 樹并渲染至屏幕中
- 狀態(tài)改變時(shí)胆绊,通過diff算法對比2課虛擬DOM樹,得到差異(patches)
- 將差異應(yīng)用到DOM樹上欧募,并將變化更新到屏幕中(進(jìn)行重新渲染)
Note: Fiber 是 React 16 中新的協(xié)調(diào)引擎压状。它的主要目的是使 Virtual DOM 可以進(jìn)行增量式渲染。了解更多.
對于首次渲染,React 的主要工作就是將 React.render 接收到的 VNode 轉(zhuǎn)化 Fiber 樹种冬,并根據(jù) Fiber 樹的層級關(guān)系镣丑,構(gòu)建生成出 DOM 樹并渲染至屏幕中。
而對于更新渲染時(shí)娱两,F(xiàn)iber 樹已經(jīng)存在于內(nèi)存中了莺匠,所以 React 更關(guān)心的是計(jì)算出 Fiber 樹中的各個(gè)節(jié)點(diǎn)的差異,并將變化更新到屏幕中十兢。
微信小程序渲染流程
MINA 是在微信中開發(fā)小程序的框架趣竣。其目標(biāo)是通過盡可能簡單、高效的方式讓開發(fā)者可以在微信中開發(fā)具有原生 APP 體驗(yàn)的服務(wù)纪挎。
MINA 提供了自己的渲染層描述語言 WXML 和 WXSS期贫,以及基于 JavaScript 的邏輯層框架,核心是一個(gè)響應(yīng)的數(shù)據(jù)綁定系統(tǒng)异袄。
小程序的運(yùn)行環(huán)境分成渲染層和邏輯層,其中 WXML 模板和 WXSS 樣式工作在渲染層玛臂,JS 腳本工作在邏輯層烤蜕。
小程序的渲染層和邏輯層分別由2個(gè)線程管理:
- 渲染層的界面使用了WebView 進(jìn)行渲染
- 邏輯層采用JsCore線程運(yùn)行JS腳本
一個(gè)小程序存在多個(gè)界面,所以渲染層存在多個(gè)WebView線程迹冤,這兩個(gè)線程的通信會(huì)經(jīng)由微信客戶端(下文中也會(huì)采用Native來代指微信客戶端)做中轉(zhuǎn)讽营,邏輯層發(fā)送網(wǎng)絡(luò)請求也經(jīng)由Native轉(zhuǎn)發(fā),小程序的通信模型下圖所示
渲染過程:
- 在渲染層泡徙,宿主環(huán)境(微信App)會(huì)把WXML轉(zhuǎn)換成對應(yīng)的JS對象(可以看作與React的VNode)
- 將JS對象再次轉(zhuǎn)換成真實(shí)DOM樹橱鹏,交由渲染層線程渲染(Weview初始化完成后的流程與瀏覽器渲染流程一致)
- 數(shù)據(jù)變化時(shí)(在小程序容器中,邏輯層到渲染層的更新堪藐,只能通過 setData() 來實(shí)現(xiàn)莉兰。),邏輯層提供最新的變化數(shù)據(jù)礁竞,生成新的JS對象與之前的JS對象進(jìn)行diff算法對比
- 將最新變化的內(nèi)容反映到真實(shí)的DOM樹中糖荒,更新UI
基于Taro Next(React)的微信小程序渲染流程
從實(shí)現(xiàn)原理上,開源社區(qū)的跨端框架大致分為下面兩類:
- compile time 編譯時(shí)
框架約定了一套自己的 DSL 模捂,在編譯打包的過程中捶朵,利用 babel 工具通過 AST 進(jìn)行轉(zhuǎn)譯,生成符合小程序規(guī)則的代碼狂男,如Taro v1/2 - runtime 運(yùn)行時(shí)
跨端框架真正的在小程序的邏輯層中運(yùn)行起 React 或者是 Vue 的運(yùn)行時(shí)综看,然后通過適配層,實(shí)現(xiàn)自定義渲染器岖食,如Taro Next
React 16版本帶來了全新的 fiber 的架構(gòu)红碑,代碼拆分也非常清晰,大體上可以拆分成這三大塊:
- React component API
- Reconciler
- Renderer
其中渲染器Renderer負(fù)責(zé)將內(nèi)容渲染到具體的平臺(tái)上县耽。最常見的 ReactDOM 就是 web 瀏覽器平臺(tái)的自定義渲染器句喷。即當(dāng)調(diào)用操作 WEB 瀏覽器 web DOM的方法镣典,如createElement、appendhild唾琼,那么就創(chuàng)建/更新瀏覽器中的 web 頁面兄春。
擴(kuò)展閱讀,【2萬字長文】深入淺出主流的幾款小程序跨端框架原理
在一個(gè)頁面加載時(shí)需要經(jīng)歷以下步驟:
- React把頁面渲染到虛擬 DOM 中
- Taro 運(yùn)行時(shí)把頁面的虛擬 DOM 序列化為JSON 樹狀數(shù)據(jù)锡溯,并使用 setData() 驅(qū)動(dòng)頁面渲染
- 小程序本身渲染序列化數(shù)據(jù)赶舆,渲染到小程序頁面
- 數(shù)據(jù)變化時(shí),通過setData()去更新上面小程序的 JSON 樹狀數(shù)據(jù)
- JSON 樹狀數(shù)據(jù)被更新了祭饭,小程序會(huì)觸發(fā)更新數(shù)據(jù)對應(yīng)的那塊視圖的渲染
基于Taro Next(React)的微信小程序渲染問題和解決方案
和原生小程序或編譯型小程序框架相比芜茵,基于Taro Next(React)的微信小程序渲染流程中的步驟 1 和 步驟 2 是新增的。如果頁面的業(yè)務(wù)邏輯代碼沒有性能問題的話倡蝙,大多數(shù)性能瓶頸出在步驟 2 的 setData() 上九串。
由于初始化渲染是頁面的整棵虛擬 DOM 樹,數(shù)據(jù)量比較大寺鸥,因此 setData() 需要傳遞一個(gè)比較大的數(shù)據(jù)猪钮,導(dǎo)致初始化頁面時(shí)會(huì)一段白屏的時(shí)間。這樣的情況通常發(fā)生在頁面初始化渲染的 wxml 節(jié)點(diǎn)數(shù)比較大或用戶機(jī)器性能較低時(shí)發(fā)生胆建。
解決方案:
- 多使用stateless component
- stateful component在setData的時(shí)候減小數(shù)據(jù)量
- 正確使用hooks dependencies, 并減少 setData 函數(shù)的調(diào)用次數(shù)
- Taro 3 官方也提供了一些種方式:
參考文檔:
https://developer.mozilla.org/zh-CN/docs/Web/Performance/How_browsers_work
https://reactjs.org/docs/rendering-elements.html#gatsby-focus-wrapper
https://reactjs.org/docs/reconciliation.html
http://yunlaiwu.github.io/blog/2017/08/14/react-virtual-dom-fiber/
https://juejin.cn/post/6923073253988810765
https://zhuanlan.zhihu.com/p/103506207
https://developers.weixin.qq.com/miniprogram/dev/framework/quickstart/framework.html
https://developers.weixin.qq.com/miniprogram/dev/framework/MINA.html
https://juejin.cn/post/6881597846307635214
https://juejin.cn/book/6844733744830480397
https://taro-docs.jd.com/taro/docs/optimized
https://docs.taro.zone/blog/2021-02-08-taro-jxpp