小程序實現原理解析
概述
作為一名前端開發,如果你還停留在應用開發層麵,那你就OUT了,快來跟我一起探討下小程序框架本身底層實現的一些技術細節吧,讓我們從小程序的運行機製來深度了解小程序。
小程序是基於WEB規範,采用HTML,CSS和JS等搭建的一套框架,微信官方給它們取了一個很牛逼的名字:WXML,WXSS,但本質上還是在整個WEB體係之下構建的。
WXML,個人猜測在取這個名字的是微信的Xml,說到底就是xml的一個子集。WXML采用微信自定義的少量標簽WXSS,大家可以理解為就是自定義的CSS。實現邏輯部分的JS還是通用的ES規範,並且runtime還是Webview(IOS WKWEBVIEW, ANDROID X5)。
小程序
小程序目錄結構
一個完整的小程序主要由以下幾部分組成:
一個入口文件:app.js
一個全局樣式:app.wxss
一個全局配置:app.json
頁麵:pages下,每個頁麵再按文件夾劃分,每個頁麵4個文件
視圖:wxml,wxss
邏輯:js,json(頁麵配置,不是必須)
注:pages裏麵還可以再根據模塊劃分子目錄,孫子目錄,隻需要在app.json裏注冊時填寫路徑就行。
小程序打包
開發完成後,我們就可以通過這裏可視化的按鈕,點擊直接打包上傳發布,審核通過後用戶就可以搜索到了。
那麼打包怎麼實現的呢?
這就涉及到這個編輯器的實現原理和方式了,它本身也是基於WEB技術體係實現的,nwjs+react,nwjs是什麼:簡單是說就是node+webkit,node提供給我們本地api能力,而webkit提供給我們web能力,兩者結合就能讓我們使用JS+HTML實現本地應用程序。
既然有nodejs,那上麵的打包選項裏的功能就好實現了。
ES6轉ES5:引入babel-core的node包
CSS補全:引入postcss和autoprefixer的node包(postcss和autoprefixer的原理看這裏)
代碼壓縮:引入uglifyjs的node包
注:在android上使用的x5內核,對ES6的支持不好,要兼容的話,要麼使用ES5的語法或者引入babel-polyfill兼容庫。
打包後的目錄結構
所有的小程序基本都最後都被打成上麵的結構
1、WAService.js 框架JS庫,提供邏輯層基礎的API能力
2、WAWebview.js 框架JS庫,提供視圖層基礎的API能力
3、WAConsole.js 框架JS庫,控製台
4、app-config.js 小程序完整的配置,包含我們通過app.json裏的所有配置,綜合了默認配置型
5、app-service.js 我們自己的JS代碼,全部打包到這個文件
6、page-frame.html 小程序視圖的模板文件,所有的頁麵都使用此加載渲染,且所有的WXML都拆解為JS實現打包到這裏
7、pages 所有的頁麵,這個不是我們之前的wxml文件了,主要是處理WXSS轉換,使用js插入到header區域。
小程序架構
微信小程序的框架包含兩部分View視圖層、App Service邏輯層,View層用來渲染頁麵結構,AppService層用來邏輯處理、數據請求、接口調用,它們在兩個進程(兩個Webview)裏運行。
視圖層和邏輯層通過係統層的JSBridage進行通信,邏輯層把數據變化通知到視圖層,觸發視圖層頁麵更新,視圖層把觸發的事件通知到邏輯層進行業務處理。
小程序啟動時會從CDN下載小程序的完整包,一般是數字命名的,如:_-2082693788_4.wxapkg
小程序技術實現
小程序的UI視圖和邏輯處理是用多個webview實現的,邏輯處理的JS代碼全部加載到一個Webview裏麵,稱之為AppService,整個小程序隻有一個,並且整個生命周期常駐內存,而所有的視圖(wxml和wxss)都是單獨的Webview來承載,稱之為AppView。所以一個小程序打開至少就會有2個webview進程,正式因為每個視圖都是一個獨立的webview進程,考慮到性能消耗,小程序不允許打開超過5個層級的頁麵,當然同是也是為了體驗更好。
AppService
可以理解AppService即一個簡單的頁麵,主要功能是負責邏輯處理部分的執行,底層提供一個WAService.js的文件來提供各種api接口,主要是以下幾個部分:
消息通信封裝為WeixinJSBridge(開發環境為window.postMessage, IOS下為WKWebview的window.webkit.messageHandlers.invokeHandler.postMessage,android下用WeixinJSCore.invokeHandler)
1、日誌組件Reporter封裝
2、wx對象下麵的api方法
3、全局的App,Page,getApp,getCurrentPages等全局方法
4、還有就是對AMD模塊規範的實現
然後整個頁麵就是加載一堆JS文件,包括小程序配置config,上麵的WAService.js(調試模式下有asdebug.js),剩下就是我們自己寫的全部的js文件,一次性都加載。
在開發環境下
1、頁麵模板:app.nw/app/dist/weapp/tpl/appserviceTpl.js
2、配置信息,是直接寫入一個js變量,__wxConfig。
3,其他配置
線上環境
而在上線後是應用部分會打包為2個文件,名稱app-config.json和app-service.js,然後微信會打開webview去加載。線上部分應該是微信自身提供了相應的模板文件,在壓縮包裏沒有找到。
1、WAService.js(底層支持)
2、app-config.json(應用配置)
3、app-service.js(應用邏輯)
然後運行在JavaScriptCore引擎裏麵。
AppView
這裏可以理解為h5的頁麵,提供UI渲染,底層提供一個WAWebview.js來提供底層的功能,具體如下:
1、消息通信封裝為WeixinJSBridge(開發環境為window.postMessage, IOS下為WKWebview的window.webkit.messageHandlers.invokeHandler.postMessage,android下用WeixinJSCore.invokeHandler)
2、日誌組件Reporter封裝
3、wx對象下的api,這裏的api跟WAService裏的還不太一樣,有幾個跟那邊功能差不多,但是大部分都是處理UI顯示相關的方法
4、小程序組件實現和注冊
5、VirtualDOM,Diff和Render UI實現
6、頁麵事件觸發
在此基礎上,AppView有一個html模板文件,通過這個模板文件加載具體的頁麵,這個模板主要就一個方法,$gwx,主要是返回指定page的VirtualDOM,而在打包的時候,會事先把所有頁麵的WXML轉換為ViirtualDOM放到模板文件裏,而微信自己寫了2個工具wcc(把WXML轉換為VirtualDOM)和wcsc(把WXSS轉換為一個JS字符串的形式通過style標簽append到header裏)。
Service和View通信
使用消息publish和subscribe機製實現兩個Webview之間的通信,實現方式就是統一封裝一個WeixinJSBridge對象,而不同的環境封裝的接口不一樣,具體實現的技術如下:
windows環境
通過window.postMessage實現(使用chrome擴展的接口注入一個contentScript.js,它封裝了postMessage方法,實現webview之間的通信,並且也它通過chrome.runtime.connect方式,也提供了直接操作chrome native原生方法的接口)
發送消息:window.postMessage(data, ‘*’);,// data裏指定 webviewID
接收消息:window.addEventListener(‘message’, messageHandler); // 消息處理並分發,同樣支持調用nwjs的原生能力。
在contentScript裏麵看到一句話,證實了appservice也是通過一個webview實現的,實現原理上跟view一樣,隻是處理的業務邏輯不一樣。
'webframe' === b ? postMessageToWebPage(a) : 'appservice' === b && postMessageToWebPage(a)
IOS
通過 WKWebview的window.webkit.messageHandlers.NAME.postMessage實現微信navite代碼裏實現了兩個handler消息處理器:
invokeHandler: 調用原生能力
publishHandler: 消息分發
Android
通過WeixinJSCore.invokeHanlder實現,這個WeixinJSCore是微信提供給JS調用的接口(native實現)
invokeHandler: 調用原生能力
publishHandler: 消息分發
微信組件
在WAWebview.js裏有個對象叫exparser,它完整的實現小程序裏的組件,看具體的實現方式,思路上跟w3c的web components規範神似,但是具體實現上是不一樣的,我們使用的所有組件,都會被提前注冊好,在Webview裏渲染的時候進行替換組裝。
exparser有個核心方法:
regiisterBehavior: 注冊組件的一些基礎行為,供組件繼承
registerElement:注冊組件,跟我們交互接口主要是屬性和事件
組件觸發事件(帶上webviewID),調用WeixinJSBridge的接口,publish到native,然後native再分發到AppService層指定webviewID的Page注冊事件處理方法。
總結
小程序底層還是基於Webview來實現的,並沒有發明創造新技術,整個框架體係,比較清晰和簡單,基於Web規範,保證現有技能價值的最大化,隻需了解框架規範即可使用已有Web技術進行開發。易於理解和開發。
MSSM:對邏輯和UI進行了完全隔離,這個跟當前流行的react,agular,vue有本質的區別,小程序邏輯和UI完全運行在2個獨立的Webview裏麵,而後麵這幾個框架還是運行在一個webview裏麵的,如果你想,還是可以直接操作dom對象,進行ui渲染的。
組件機製:引入組件化機製,但是不完全基於組件開發,跟vue一樣大部分UI還是模板化渲染,引入組件機製能更好的規範開發模式,也更方便升級和維護。
多種節製:不能同時打開超過5個窗口,打包文件不能大於1M,dom對象不能大於16000個等,這些都是為了保證更好的體驗。
最後更新:2017-04-01 16:41:01