目錄
一、說在前面
二、從微信小程序的發(fā)展史說起
三、微信小程序原理分析
- 快速加載和原生的體驗
- 渲染層
- 預(yù)加載
- 基礎(chǔ)庫內(nèi)部優(yōu)化
- 注入小程序WXML結(jié)構(gòu)和WXSS樣式
- 邏輯層
四、看看JavaScriptCore是怎么執(zhí)行JS腳本的
五、再說說支付寶小程序
- 運行時架構(gòu)
- 小程序SDK
六、最后
一、說在前面:
小程序自誕生以來。就以一種百家爭鳴的姿態(tài)展現(xiàn)在開發(fā)者的面前。繼2017年1月9日微信小程序誕生后,小程序市場又陸續(xù)出現(xiàn)了支付寶小程序、頭條小程序、百度智能小程序等等。各家都在微信小程序的基礎(chǔ)上,面向自己的業(yè)務(wù),對架構(gòu)進行逐步優(yōu)化調(diào)整,但是萬變不離其宗,微信小程序終歸為小程序鼻祖,也是得益于微信小程序的思想,才造就了如今這百花齊放的業(yè)態(tài)。說起微信小程序,在體驗上的優(yōu)化,讓我很長一段時間認(rèn)為,這是 Native 層渲染。事實并不完全是,至今不敢相信,webView 的渲染竟能帶來如此體驗。本篇主要以一個客戶端開發(fā)者的角度,來對微信小程序、支付寶小程序一探究竟。本篇旨在原理分析,我并未有真實的小程序架構(gòu)設(shè)計經(jīng)驗。
說到小程序,不得不需要指出另外一個問題,蘋果爸爸對于 HTML5 app 的更新的審核問題,目前會有開發(fā)者存在這樣的疑問,Hybrid 和 H5 是不是要被蘋果拒審了呢?其實從更新描述來看,不難發(fā)現(xiàn)蘋果的主要目的是針對“核心功能未在二進制文件內(nèi)”的 App ,實際上小程序無論是在設(shè)計理念上,還是核心技術(shù)上,都不存在這樣的問題,小程序并非App,小程序是以 App 為載體,盡可能的對 web 頁面進行優(yōu)化而生成的產(chǎn)物。還有一點是馬甲包日益猖獗,馬甲包最后基本都轉(zhuǎn)化成為了條款內(nèi)描述的“現(xiàn)金B(yǎng)ocai、彩票抽獎和慈善捐款”類型,所以蘋果想要盡可能的禁止它。而且從微信小程序開發(fā)文檔來看,微信小程序是典型的技術(shù)推動產(chǎn)品的結(jié)果。關(guān)于RN類技術(shù),更不存在這樣的問題了,RN本質(zhì)為 JS 通過 JSCore 調(diào)用 Native 組件。實際上它的核心仍然在 Native 端,當(dāng)然對 code push 我還尚存疑問。關(guān)于 RN 的動態(tài)更新上,從bang's的描述也不難發(fā)現(xiàn)蘋果爸爸的態(tài)度,只要不是為了繞過審核去做動態(tài)更新就可以接受。
二、從微信小程序的發(fā)展史說起
微信小程序是什么,微信把小程序定義為是一種全新的連接用戶與服務(wù)的方式,它可以在微信內(nèi)被便捷地獲取和傳播,同時具有出色的使用體驗。便捷和出色有何而來?小程序技術(shù)最初來源于 H5 和 Native 間的簡單調(diào)用,微信構(gòu)建了一個 WeixinJSBridge 來為H5提供一些 Native 的功能,例如地圖、播放器、定位、拍照、預(yù)覽等功能。關(guān)于 Bridge 的具體實現(xiàn)可以參考《寫一個易于維護使用方便性能可靠的Hybrid框架》。但是微信逐漸的又遇到了另外一個問題,那就是 H5 頁面的體驗問題,微信團隊為了解決 H5 頁面的白屏問題,他們引入了最近很火的離線包概念,當(dāng)然微信稱之為微信 Web 資源離線存儲,實際上是一個東西。Web 開發(fā)者可借助微信提供的資源存儲能力,直接從微信本地加載 Web 資源而不需要再從服務(wù)端拉取,從而減少網(wǎng)頁的加載時間。關(guān)于離線包的概念,不了解的話可以參考《web離線技術(shù)原理》
。但是當(dāng)頁面加載大量 CSS 和 JS 時,依然會有白屏問題,包括 H5 頁面點擊事件的遲鈍感和頁面跳轉(zhuǎn)的體驗問題。那么基于此問題,應(yīng)運而生的,小程序技術(shù)就誕生了。
從微信小程序的發(fā)展史,不難看出,小程序?qū)嶋H上是近幾年開發(fā)者對 H5 體驗優(yōu)化而來的,這也切合了前面所說的,小程序?qū)嶋H上是典型的技術(shù)推動產(chǎn)品的結(jié)果。
三、微信小程序原理分析
微信小程序自稱能夠解決以下問題:
- 快速的加載。
- 更強大的能力。
- 原生的體驗。
- 易用且安全的微信數(shù)據(jù)開發(fā)。
- 高效和簡單的開發(fā)。
快速加載和原生的體驗,這其實都是在體驗上的升級,更強大能力實際上源于微信小程序為開發(fā)者提供了大量的組件,這些組件有基于web技術(shù),也有基于Native技術(shù),在我看來這和 RN 技術(shù)不謀而合。后面我會舉一個模仿 RN 實現(xiàn)的小例子來闡述一下它的原理。
高效和簡單的開發(fā)是因為微信小程序開發(fā)語言實質(zhì)上還是基于 web 開發(fā)規(guī)范,這使得開發(fā)前端的人來開發(fā)小程序顯得更容易。
還有一點更重要的就是安全,為什么說小程序是安全的?后面會逐步展開,揭開小程序的神秘面紗。
快速加載和原生的體驗
小程序的架構(gòu)設(shè)計與 web 技術(shù)還是有一定的差別,吸取了 web 技術(shù)的一些優(yōu)勢,也摒棄了 web 技術(shù)中體驗不好的地方。最主要的特點就是小程序采用雙線程機制,即視圖渲染和業(yè)務(wù)邏輯分別運行在不同的線程中。在傳統(tǒng)的 web 開發(fā)中,網(wǎng)頁開發(fā)渲染線程和腳本線程是互斥的,所以 H5 頁面中長時間的腳本運行可能會導(dǎo)致頁面失去響應(yīng)或者白屏,體驗糟糕。
為了更好的體驗,將頁面渲染線程和腳本線程分開執(zhí)行:
- 渲染層:界面渲染相關(guān)的邏輯全部 在webView 線程內(nèi)執(zhí)行,一個小程序存在多個頁面,一個頁面對應(yīng)一個 webView,微信小程序限制開發(fā)者最多只能創(chuàng)建五個頁面。
- 邏輯層:Android采用 JSCore ,iOS采用的 JavaScriptCore 框架運行 JS 腳本。怎么在 JavaScriptCore 運行腳本文件后面會講。
雙線程模型是小程序框架與大多數(shù)前端 web 框架的不同之處,基于這個模型可以更好的管控以及提供更安全的環(huán)境。因為邏輯層運行在 JSCore 中,并沒有一個完整瀏覽器對象,因而缺少相關(guān)的DOM API和BOM API。客戶端的開發(fā)者可能對 DOM 有些陌生,了解編譯過程的同學(xué)應(yīng)該知道在編譯器編譯代碼的時候,會有一個語法分析的過程,生成抽象語法樹 AST,編譯器會根據(jù)語法樹去檢查表達(dá)式是否合法、括號是否匹配等。實際上DOM也是一種樹結(jié)構(gòu),經(jīng)過瀏覽器的解析,最終呈現(xiàn)在用戶面前。通過 JavaScript 操縱 DOM 可以隨意改變元素的位置,這對于小程序來說是極為不安全的。所以說邏輯層為小程序帶來的另一個特點,易于管控和安全。線程通信基于前面提到的 WeixinJSBridge :邏輯層把數(shù)據(jù)變化通知到視圖層,觸發(fā)視圖層頁面的更新,視圖層把觸發(fā)的事件通知到邏輯層進行業(yè)務(wù)處理。
當(dāng)我們對渲染層進行事件操作后,會通過 WeixinJSBridge 將數(shù)據(jù)傳遞到 Native 系統(tǒng)層。Native 系統(tǒng)層決定是否要用 Native 處理,然后丟給 邏輯層進行用戶的邏輯代碼處理。邏輯層處理完畢后會將數(shù)據(jù)通過 WeixinJSBridge 返給 View 層,View 渲染更新視圖。
渲染層
根據(jù)《微信小程序開發(fā)者文檔》描述,在視圖層內(nèi),小程序的每一個頁面都獨立運行在一個頁面層級上。小程序啟動時僅有一個頁面層級,每次調(diào)用wx.navigateTo,都會創(chuàng)建一個新的頁面層級;相對地,wx.navigateBack會銷毀一個頁面層級。大概可以理解為,每個 web 頁面都是運行在單獨的 webView 里面,這樣的好處就是讓每個 webView 單純的處理當(dāng)前頁面的渲染邏輯,不需要加載其他頁面的邏輯代碼,減輕負(fù)擔(dān)能夠加速頁面渲染,使其能夠盡可能的接近原生,這與小程序跳轉(zhuǎn)頁面的體驗上也是一致的。
實際上在小程序源碼內(nèi)有一個 index.html 文件的存在,這是小程序啟動后的入口文件。初次加載的時候,主入口會加載相應(yīng)的 webView ,這其中就會包括前面所提到的,視圖層和邏輯層。邏輯層雖然也提供了 webView ,但是并不提供瀏覽器相關(guān)接口,而是單純的為了獲取當(dāng)前的 JSCore ,執(zhí)行相關(guān)的 JS 腳本文件,這也是開發(fā)小程序是沒辦法直接操作 DOM 的根本原因。
當(dāng)我們每打開一個新頁面的時候,調(diào)用 navigateTo 都相當(dāng)于打開了一個新的 webView ,這樣一直打開,內(nèi)存也會變得吃緊,這也是為什么小程序?qū)撁娲蜷_數(shù)量有限制的原因了。
預(yù)加載
根據(jù)小程序開發(fā)文檔描述:對于每一個新的頁面層級,視圖層都需要進行一些額外的準(zhǔn)備工作。在小程序啟動前,微信會提前準(zhǔn)備好一個頁面層級用于展示小程序的首頁。除此以外,每當(dāng)一個頁面層級被用于渲染頁面,微信都會提前開始準(zhǔn)備一個新的頁面層級,使得每次調(diào)用wx.navigateTo都能夠盡快展示一個新的頁面。這在客戶端的角度來看,相當(dāng)于打開新頁面之后,對下一個頁面的 webView 提前做了預(yù)加載,這個思路與當(dāng)前比較流行的 webView 緩存池的思路不謀而合,原因是在 iOS 和 Android 系統(tǒng)上,操作系統(tǒng)啟動 webView 都需要一小段時間,預(yù)加載會提升頁面打開速度,優(yōu)化白屏問題。
基礎(chǔ)庫內(nèi)部優(yōu)化
再往深層次來看,通過小程序開發(fā)工具的源碼,能找到一個 pageframe.html 的模版文件,具體位置在package.nw/html/pageframe.html:
看標(biāo)題就應(yīng)該很清楚了,這是渲染層的核心模塊,它的作用就是為小程序準(zhǔn)備一個新的頁面,小程序每個視圖層頁面內(nèi)容都是通過 pageframe.html 模板來生成的,包括小程序啟動的首頁。通過查看源碼,里面定義了一個屬性var __webviewId__,我猜想這是每個 webView 頁面的頁面 ID ,邏輯層處理多個視圖層間的業(yè)務(wù)邏輯可能就是通過這個ID來做的映射關(guān)系。在首次啟動時,后臺會緩存生成的 pageframe.html 模版,在后面的頁面打開時,直接加載緩存的 pageframe.html 模版,頁面引入的資源文件也可以直接在緩存中加載,包括小程序基礎(chǔ)庫視圖層底層、頁面的模版信息、配置信息以及樣式等內(nèi)容,這樣避免重復(fù)生成,快速打開頁面,提升頁面渲染性能。
注入小程序WXML結(jié)構(gòu)和WXSS樣式
關(guān)于 pageframe.html 最后是怎么生成相應(yīng)頁面的歸功于一個叫 nw.js 的框架,具體實現(xiàn)這里就不講了(主要是我不會)。
邏輯層
上面了解了渲染層都做了什么之后,下面在窺探一下,小程序的邏輯層都做了什么。參考http://eux.baidu.com/blog/fe/微信小程序架構(gòu)原理不難發(fā)現(xiàn),sevice 層的代碼是由 WAService.js 實現(xiàn)的,邏輯層實際上主要提供了 Page, App,GetApp 接口和更為豐富 wx 接口模塊,包括數(shù)據(jù)綁定、事件分發(fā)、生命周期管理、路由管理等等。關(guān)于視圖層和邏輯層間的具體交互細(xì)節(jié)可以看下這張圖:
我們寫的頁面邏輯最后都被引入到了一個叫 appservice.html 的頁面中,并且分別從 app.js 開始一一執(zhí)行;小程序代碼調(diào)用 Page 構(gòu)造器的時候,小程序基礎(chǔ)庫會記錄頁面的基礎(chǔ)信息,如初始數(shù)據(jù)(data)、方法等。需要注意的是,如果一個頁面被多次創(chuàng)建,并不會使得這個頁面所在的JS文件被執(zhí)行多次,而僅僅是根據(jù)初始數(shù)據(jù)多生成了一個頁面實例(this),在頁面 JS 文件中直接定義的變量,在所有這個頁面的實例間是共享的。對于邏輯層,從客戶端的角度看,我們應(yīng)該更關(guān)注于邏輯層的JS是怎么注入到JSCore中的。
四、看看JavaScriptCore是怎么執(zhí)行JS腳本的
說到JavaScriptCore,我們先來討論下Hybrid App 的構(gòu)建思路,Hybird App是指混合模式移動應(yīng)用,即其中既包含原生的結(jié)構(gòu)又有內(nèi)嵌有 Web 的組件。這種 App 不僅性能和用戶體驗可以達(dá)到和原生所差無幾的程度,更大的優(yōu)勢在于 bug 修復(fù)快,版本迭代無需發(fā)版。Hybird App的實質(zhì)并沒有修改原生 Native 的行為,而是將下發(fā)的資源進行加載和界面渲染,類似 WebView。下面通過一個例子來模擬一下 JavaScriptCore 執(zhí)行 JS 腳本來讓 Native 和 JS 之間的通信。關(guān)于 JavaScriptCore 的具體使用可以參考下戴銘的《深入剖析 JavaScriptCore》。
我們打算實現(xiàn)這樣的功能:通過下發(fā)JS腳本創(chuàng)建原生的 UILabel 和 UIButton 控件并響應(yīng)事件,首先編寫 JS 代碼如下:
(function(){
console.log("ProgectInit");
//JS腳本加載完成后 自動render界面
return render();
})();
//JS標(biāo)簽類
function Label(rect,text,color){
this.rect = rect;
this.text = text;
this.color = color;
this.typeName = "Label";
}
//JS按鈕類
function Button(rect,text,callFunc){
this.rect = rect;
this.text = text;
this.callFunc = callFunc;
this.typeName = "Button";
}
//JS Rect類
function Rect(x,y,width,height){
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
//JS顏色類
function Color(r,g,b,a){
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
//渲染方法 界面的渲染寫在這里面
function render(){
var rect = new Rect(20,100,280,30);
var color = new Color(1,0,0,1);
var label = new Label(rect,"這是一個原生的Label",color);
var rect4 = new Rect(20,150,280,30);
var button = new Button(rect4,"這是一個原生的Button",function(){
var randColor = new Color(Math.random(),Math.random(),Math.random(),1);
TestBridge.changeBackgroundColor(randColor);
});
//將控件以數(shù)組形式返回
return [label,button];
}
創(chuàng)建一個 OC 類 TestBridge 綁定到 JavaScriptCore 全局對象上:
@protocol TestBridgeProtocol <JSExport>
- (void)changeBackgroundColor:(JSValue *)value;
@end
@interface TestBridge : NSObject<TestBridgeProtocol>
@property(nonatomic, weak) UIViewController *ownerController;
@end
#import "TestBridge.h"
@implementation TestBridge
- (void)changeBackgroundColor:(JSValue *)value{
self.ownerController.view.backgroundColor = [UIColor colorWithRed:value[@"r"].toDouble green:value[@"g"].toDouble blue:value[@"b"].toDouble alpha:value[@"a"].toDouble];
}
@end
在 ViewController 中實現(xiàn)一個界面渲染的 render 解釋方法:
#import "ViewController.h"
#import <JavaScriptCore/JavaScriptCore.h>
#import "TestBridge.h"
@interface ViewController ()
@property(nonatomic, strong)JSContext *jsContext;
@property(nonatomic, strong)NSMutableArray *actionArray;
@property(nonatomic, strong)TestBridge *bridge;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
//創(chuàng)建JS運行環(huán)境
self.jsContext = [JSContext new];
//綁定橋接器
self.bridge = [TestBridge new];
self.bridge.ownerController = self;
self.jsContext[@"TestBridge"] = self.bridge;
self.actionArray = [NSMutableArray array];
[self render];
}
-(void)render{
NSString * path = [[NSBundle mainBundle] pathForResource:@"main" ofType:@"js"];
NSData * jsData = [[NSData alloc]initWithContentsOfFile:path];
NSString * jsCode = [[NSString alloc]initWithData:jsData encoding:NSUTF8StringEncoding];
JSValue * jsVlaue = [self.jsContext evaluateScript:jsCode];
for (int i=0; i<jsVlaue.toArray.count; i++) {
JSValue * subValue = [jsVlaue objectAtIndexedSubscript:i];
if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Label"]) {
UILabel * label = [UILabel new];
label.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);
label.text = subValue[@"text"].toString;
label.textColor = [UIColor colorWithRed:subValue[@"color"][@"r"].toDouble green:subValue[@"color"][@"g"].toDouble blue:subValue[@"color"][@"b"].toDouble alpha:subValue[@"color"][@"a"].toDouble];
label.textAlignment = NSTextAlignmentCenter;
[self.view addSubview:label];
}else if ([[subValue objectForKeyedSubscript:@"typeName"].toString isEqualToString:@"Button"]){
UIButton * button = [UIButton buttonWithType:UIButtonTypeSystem];
button.frame = CGRectMake(subValue[@"rect"][@"x"].toDouble, subValue[@"rect"][@"y"].toDouble, subValue[@"rect"][@"width"].toDouble, subValue[@"rect"][@"height"].toDouble);
[button setTitle:subValue[@"text"].toString forState:UIControlStateNormal];
button.tag = self.actionArray.count;
[button addTarget:self action:@selector(buttonAction:) forControlEvents:UIControlEventTouchUpInside];
[self.actionArray addObject:subValue[@"callFunc"]];
[self.view addSubview:button];
}
}
}
-(void)buttonAction:(UIButton *)btn{
JSValue * action = self.actionArray[btn.tag];
[action callWithArguments:nil];
}
@end
這樣就完成了一個簡單的 JS 腳本注入,實際上執(zhí)行后的樣子是這樣的:
這就是一個簡單的執(zhí)行 JS 腳本的邏輯,實際上 ReactNative 的原理也是基于此,小程序邏輯層與微信客戶端的交互邏輯也是基于此。
到這里,關(guān)于微信小程序渲染層與邏輯層做了什么、怎么做的、優(yōu)化了什么以及為什么要采用這樣的架構(gòu)來設(shè)計,基本都梳理完畢了。小程序這樣的分層設(shè)計顯然是有意為之的,它的中間層完全控制了程序?qū)τ诮缑孢M行的操作, 同時對于傳遞的數(shù)據(jù)和響應(yīng)時間也做到的監(jiān)控。一方面程序的行為受到了極大限制, 另一方面微信可以確保他們對于小程序內(nèi)容和體驗有絕對的控制。我們在小程序的 JS 代碼里面是不能直接使用瀏覽器提供的 DOM 和 BOM 接口的,這一方面是因為 JS 代碼外層使用了局部變量進行屏蔽,另一方面即便我們可以操作 DOM 和 BOM 接口,它們對應(yīng)的也是邏輯層模塊,并不會對頁面產(chǎn)生影響。這樣的結(jié)構(gòu)也說明了小程序的動畫和繪圖 API 被設(shè)計成生成一個最終對象而不是一步一步執(zhí)行的樣子, 原因就是 json 格式的數(shù)據(jù)傳遞和解析相比與原生 API 都是損耗不菲的,如果頻繁調(diào)用很可能損耗 過多性能,進而影響用戶體驗。
總結(jié)一句話就是webView渲染,JSCore處理邏輯,JSBridge做線程通信。后面再簡要的分析下支付寶小程序,支付寶小程序?qū)儆诤笃鹬悖Ц秾毿〕绦蛟谖⑿判〕绦虻幕A(chǔ)上,做了一些優(yōu)化,單從技術(shù)角度來看,有點后來者居上的意思。目前支付寶技術(shù)通過官方的媒體賬號對外暴漏的一些實現(xiàn)細(xì)節(jié)也在逐步增多。
六、再說說支付寶小程序
前端框架下面是小程序 native 引擎,包括了小程序容器、渲染引擎和 JavaScript 引擎,這塊主要是把客戶端 native 的能力和前端框架結(jié)合起來,給開發(fā)者提供系統(tǒng)底層能力的接口。在渲染引擎上面,支付寶小程序不僅提供 JavaScript+Webview 的方式,還提供 JavaScript+Native 的方式,在對性能要求較高的場景,可以選擇 Native 的渲染模式,給用戶更好的體驗。
這段文字來源于支付寶對外開放的技術(shù)博客的描述,從這段描述中,我們能夠發(fā)現(xiàn)支付寶小程序在架構(gòu)設(shè)計上同樣采用的渲染引擎加 JavaScript 引擎兩部分,包括頁面間的切換實際上和微信小程序邏輯基本一致。下面這張是支付寶小程序應(yīng)用框架的架構(gòu)圖:
運行時架構(gòu)
單從這個運行時架構(gòu)來看,它與微信小程序不同的地方是,webView 頁面也就是渲染層通過消息服務(wù)直接與邏輯層進行通訊,而不需要像微信的 JSBridge 那樣作為中間層,消息服務(wù)具體實現(xiàn)細(xì)節(jié)目前尚不得知。支付寶的JSBridge只會與邏輯層進行通訊,來給小程序提供一些 Native 能力。支付寶的這種架構(gòu)主要目的是解決渲染層與邏輯層交互的對象較復(fù)雜、數(shù)據(jù)量較大時,交互的性能比較差的問題。支付寶小程序的設(shè)計思路比較值得借鑒,微信小程序線程間的通訊是通過 JSBridge ,序列化 json 進行傳遞的。支付寶小程序重新設(shè)計了V8虛擬機,讓邏輯和渲染都有自己的 Local Runtime,存放私有的模塊和數(shù)據(jù)。在渲染層和邏輯層交互時,setData 的 對象會直接創(chuàng)建在 Shared Heap 里面,因此渲染層的 Local Runtime 可以直接讀到該對象,并且用于 render 層的渲染,保證了邏輯和渲染的隔離,又減少了序列化和傳輸成本。當(dāng)然支付寶還有些其他的優(yōu)化,包括首頁離線緩存,緩存時機的處理以及閃屏處理等等問題,這里就不再延伸討論了(因為很多細(xì)節(jié)我也不知道??)。
小程序SDK
根據(jù)支付寶小程序?qū)ν忾_放的技術(shù)文章來看,架構(gòu)設(shè)計還是非常巧妙的,也很值得我們學(xué)習(xí),先看圖:
參考:《獨家!支付寶小程序技術(shù)架構(gòu)全解析》
小程序SDK在架構(gòu)設(shè)計上把它分為了兩部分,一部分是核心庫基礎(chǔ)引擎,一部分是基于基礎(chǔ)庫開發(fā)的插件功能。從上往下看:
- 第一層小程序?qū)樱@是小程序開發(fā)者使用小程序 DSL 及各種組件開發(fā)的代碼層。
- 第二層和第三層架應(yīng)該是小程序內(nèi)部封裝的一些組件和對外提供的相關(guān)API等。
- 第四層和第五層是基于 React 框架,構(gòu)建的小程序運行基礎(chǔ)框架,這是小程序的核心層,主要包含小程序的邏輯處理引擎及渲染層。支付寶基于 ReactNative 增加了 Native 引擎,可以用原生來渲染 UI 。根據(jù)支付寶 mPaaS 的介紹來看,目前支付寶的小程序使用的是 React 版,螞蟻內(nèi)部的其他 App 有在使用 React Native 版的小程序。
- 基礎(chǔ)組件部分和擴展能力部分更像是基于 Bridge 調(diào)用的原生能力。擴展能力應(yīng)該是支付寶內(nèi)部的一些基礎(chǔ)組件,一樣通過JSBridge給小程序進行賦能。
支付寶小程序架構(gòu)設(shè)計上采用分層的設(shè)計,邏輯非常清晰。在管控上,和微信小程序基本一致,使用自己的一套 DSL 來保證它的管控能力,編寫小程序只能使用框架提供的自定義的模板樣式,既保證了安全性,又解決了H5開發(fā)質(zhì)量參差不齊的問題。
六、最后
差不多半年多沒有寫文章了,這一年幾乎把所有的精力都撲在了公司的業(yè)務(wù)上,趁著公司年會時間稍顯充裕,對當(dāng)前的小程序架構(gòu)進行了下分析和總結(jié),順便參加下掘金的征文活動。當(dāng)然,真正的小程序應(yīng)該比這還要復(fù)雜的多,小程序?qū)嶋H上是多年來大前端融合的一個結(jié)果,是一套非常成體系的技術(shù)方案,是技術(shù)推動產(chǎn)品而產(chǎn)生的概念??戳诉@么多我想你對小程序也有了初步認(rèn)識,小程序的核心實際上還是渲染層和邏輯層的構(gòu)建,那么如果讓你開發(fā)一套小程序SDK,你會怎樣設(shè)計它們呢?