前言
昨日看朋友圈,據說有人花錢買star,不知道真的假的?以前以為只是大家開玩笑。今日早讀文章由百度EUX@田光宇投稿分享。
正文從這開始~~
微信小程序包含下面四種文件:
json 配置文件
wxml 小程序專用 xml 文件
wxss 小程序專用 css 文件
{{ text }}
Page({
data:{
text:"這是一個頁面"
},
:(){
// 頁面初始化 為頁面跳轉所帶來的參數
},
// ........
})
微信小程序只能通過其 mvvm 的模板語法來動態改變頁面,本身 js 并不支持 BOM 和 DOM 操作。
從開發工具看微信小程序架構
在 mac 端直接解壓應用 發現 app.nw 文件夾,即開發工具源碼。可以知道該項目由 nw.js 編寫; 在 .json 文件下找到應用入口:app/html/index.html。入口 js 為 dist/app.js 我們可以看到整個編輯器的大致邏輯。
但我們關心的是構建過程,在 weapp 文件夾下存在 build.js 文件。沒有找到有用的信息,只看到了 模塊,包括對大小限制,上傳包命名。
為此懷疑微信小程序系統原理圖,微信小程序本身和 RN 類似。是在服務端打包成 語言的。但是通過, 邊框測試發現,微信小程序根本不是 原生內容。且,我們在開發工具上寫 微信語法,竟然可以直接預覽。說明一定有問題。
原生長這樣的
編譯過程
繼續在 trans 文件夾下發現了編譯模板。
wxml 轉 js
wxss 轉 css
模板頁配置
wxml 轉 html
管理器
用到的內容:
發現用到了一個模板:app.nw/app/dist/weapp/tpl/.js, app.mw/app.dist.weapp/tpl/.js
wcc 可執行程序,wcc用于轉轉wxml中的自定義tag為
wcsc 可執行程序,用于將 wxss 轉為 view 模塊使用的 css 代碼,使用方式為 wcsc xxx.wxss
在模板中,我們發現使用了 .js 文件,.js文件。 在 中我們發現一段 事件的函數。對比注冊該事件的函數在 .js 中。
我們嘗試使用 wcc 對input.xml 文件進行編譯。
wcc -d input.xml
生成了一段腳本:
. = 'v0.'
var $gwxc
var $gaic =
$gwx = (path, ) {
_(a, b) {
b && a..push(b);
}
....
通過代碼我們發現,調用 $gwx 函數會再生成一個有返回值的函數(前提是 path 填寫正確);于是我們執行如下代碼:
$gwx("input.xml")("test")
得出如下內容:
{
"tag": "wx-page",
"": [
{
"tag": "wx-view",
"attr": {
"class": ""
},
"": [
{
"tag": "wx-input",
"attr": {
"": true,
"": "這是一個可以自動聚焦的input"
},
"": []
}
]
}
]
}
這應該是一個類似 dom 的對象,交給了 .js 來渲染,標簽名為 wx-view, wx-input。
.js
代碼在最一開始提供的是兼容性工具,還有一個 引入。
接下來是一個 對象,它的作用就是發送錯誤和性能統計數據給后臺。
wx 核心對象,包含了 wx 對象下的 api。但是這里的 api 數量遠遠少于官方的 api 文檔數量。
我們可以再代碼里面發現,wx 下注冊的 api 最終都會調用 方法,這個方法。應該是在打包的時候端上注入的。然而,我們也可以在 .js 中找到該方法的定義。
所以我們得到了一個結論,.js 是編輯器用來接受 wx 方法回調的代碼。
對象,提供 dom 到 wx 對象之間的映射操作,提供元素操作管理和事件管理功能。
接都是對 對象的處理,包括注冊 全局事件, dom 算法實現,樣式注入等。介紹幾個組件重要的內容
. 注冊組件基礎行為微信小程序系統原理圖,供組件繼承。
. 為各種內置組件,注冊模板,行為,屬性,監聽器等內容
這里我們觀察到,組件:wx-video, wx-, wx--, wx-map, wx- 等 都含有 “wx-” 屬性。這是不是意味著,這類組件都是 原生實現的呢。我們打開邊框檢查,發現這類組件確實都時原生的組件。
綜上,微信小程序的界面有部分組件使用原生方式實現的,組件層在層之上。大部分還是用前端實現的,這樣解釋了微信小程序的一個bug。
因為 -view 是前端實現,在里面使用 組件,這樣就無法監聽滾動了。
組件是需要數據來渲染的,查看文檔我們知道發送請求的 api 為 wx.;通過上面分析,我么你知道 wx. 實際調用的是 。現在我們看看
真正發送處理數據請求的時這端代碼;如果當前環境是 ios, 那么調用 的 ....。如果所處環境是 則調用 .(調用的時候,默認會帶上當前 )。
.js
在我們看的 .js 分析中,我們并沒有發現前端的通訊實現,路由能力,數據綁定等級制。進一步查看找到了一個 .js 文件。 查看 .js 文件源碼:
在代碼最開始,跟 .js 一樣的 兼容模塊
然后是跟 .js 一樣的 模塊。
比 .js 中 wx 功能更為豐富 wx 接口模塊。(剩余的那部分 wx api 都在這里)
模塊,提供 Page,App, 接口
為 對象添加 AMD 接口
綜上,.js 主要實現的功能:
App( ) 小程序的入口;Page( ) 頁面的入口
wx API;
頁面有的作用域,提供模塊化能力
數據綁定、事件分發、生命周期管理、路由管理
到這里我們得出結論,小程序的架構方案:
整個小程序由兩個 組成,代碼分為 UI 層和邏輯層。UI 層運行在第一個 當中,執行 DOM 操作和交互事件的響應,里面是 .js 代碼及編譯后的內容。邏輯層執行在(第二個 中)獨立的 JS 引擎中(iOS:, :X5 JS解析器;統稱 ;開發工具中,nwjs 內核),.js 代碼和業務邏輯。
當我們對 view 層進行事件操作后,會通過 將數據傳遞到 系統層。 系統層決定是否要用 處理,然后丟給 邏輯層進行用戶的邏輯代碼處理。邏輯層處理完畢后會將數據通過 返給 View 層。View 渲染更新視圖。
架構的討論
微信的這種架構,對邏輯和UI進行了完全隔離,小程序邏輯和UI完全運行在2個獨立的里面來處理。那么這么做的好處是啥?總感覺更加麻煩了。除了小程序外,還有人采用這種架構設計么?
在網上搜索了一下,目前使用這種架構的項目還真有一個:去哪兒最新的 YIS 框架
YIS 采取了類似小程序的架構,分為邏輯層和UI層。UI 層運行在 中,而邏輯層運行在獨立的 JS 引擎中。相應地,整個應用的代碼,也分為兩個大的部分,一部分運行在 中,一部分運行在JS引擎中。JS引擎計算DOM結構輸出給,轉發用戶的點擊事件給JS引擎。
該項目做法和小城十分類似,唯一缺少的就是沒有 的組件吧。然而官方文檔上也沒有任何介紹,為什么要這么做,只是說更流暢了。
一些看法
傳統 web 頁面顯示需要經歷一下幾個步驟:
初始化
加載 HTML, CSS, JS
編譯 JS
計算
DOM Path
而利用小程序架構后,我們就可以將上述過程拆解成兩部分并行執行: 部分:
初始化
加載 HTML,CSS, JS (經過拆分后,體積大幅度減小)
編譯 JS
等待頁面需要的數據
反序列化數據
執行 Patch
渲染頁面
等待更多消息
部分:
初始化
加載框架 js 代碼
編譯 js
加載業務邏輯 js 代碼
編譯 js
計算首屏虛擬 DOM 結構
序列化數據,傳輸
等待 消息,或者 消息
這樣渲染進程和邏輯進程分離,并行處理:加速首屏渲染速度;避免單線程模型下,js 運算時間過長,UI 出現卡頓。 完全采用數據驅動的方式,不能直接操作 DOM,避免低質量的代碼。 和 可以預
當然這種架構方案也有這一定的缺點:
不能靈活操作 DOM,無法實現較為復雜的愛的暖效果
部分和 NA 相關的視圖有使用限制,如微信的 內不能有 。
頁面大小、打開頁面數量都受到限制
需要單獨開發適配,不能復用現有代碼資源。
參考資料
微信小程序底層的實現原理是怎樣的
微信小程序架構解析,工作原理解析
微信小程序架構分析