在前端越來(lái)越火的年代,逐漸衍生出類(lèi)似React Native、Weex等開(kāi)發(fā)套件。所達(dá)到的目的挺簡(jiǎn)單的,達(dá)到在多個(gè)平臺(tái)下共用一份代碼,節(jié)省開(kāi)發(fā)成本,提高開(kāi)發(fā)效率。其次,由于JavaScript語(yǔ)言的特殊性,能動(dòng)態(tài)更新頁(yè)面而不需要發(fā)版。基于這兩點(diǎn),越來(lái)越多的個(gè)人開(kāi)發(fā)者&公司開(kāi)始嘗試它們。

本文將從個(gè)人開(kāi)發(fā)實(shí)踐項(xiàng)目出發(fā),發(fā)表一些對(duì)于Weex的看法和在項(xiàng)目中的實(shí)戰(zhàn)經(jīng)歷。不涉及具體原理和概念性的東西,讀者可以自行去Weex官網(wǎng)查閱。
Weex原理
大體上和React Native一致,都是一個(gè)“放大版”的JSBrdige。其核心無(wú)非就是自定義了一套DSL(.we),配合vue實(shí)現(xiàn)數(shù)據(jù)綁定、vdom等等功能。再通過(guò)native端與JS端的數(shù)據(jù)、API交互使得最終體現(xiàn)為native的調(diào)用過(guò)程。
而在這過(guò)程中,iOS用了自帶的引擎JavaScriptCore & Android則是Google V8。在這過(guò)程中有個(gè)坑,iOS版本W(wǎng)eex有內(nèi)存泄漏的情況(Android沒(méi)有),原因是JS Framework(Weex JS端的主程)并沒(méi)有像V8一樣hidden class的行為,GC回收不是很及時(shí)。Weex開(kāi)發(fā)團(tuán)隊(duì)的同事發(fā)現(xiàn)了此bug,并在后續(xù)的版本中修復(fù)。
OK,我認(rèn)為對(duì)于“應(yīng)用框架者”來(lái)說(shuō),不用去care具體實(shí)現(xiàn)的原理。只需要了解怎么使用即可,畢竟這只是一個(gè)工具。如果是為了學(xué)習(xí),可以去閱讀,而對(duì)于“使用者”來(lái)說(shuō),快速地入門(mén)則是王道。
而Weex的使用,對(duì)于native來(lái)說(shuō),無(wú)非就是針對(duì)具體的業(yè)務(wù)場(chǎng)景實(shí)現(xiàn)Handler、Module、Component。
Handler
我們可以把Weex看做是一個(gè)提供了基礎(chǔ)套件的UI渲染庫(kù)。核心功能還是需要開(kāi)發(fā)者自己來(lái)實(shí)現(xiàn),比如:圖片下載邏輯、網(wǎng)絡(luò)請(qǐng)求、導(dǎo)航跳轉(zhuǎn)等等。
所以開(kāi)發(fā)者首先要關(guān)注的就是需要靜態(tài)分析自己當(dāng)前工程所需的功能,看看Weex需要你實(shí)現(xiàn)的handler中有哪些你要用到的,并實(shí)現(xiàn)它們。
比如在我的項(xiàng)目中,就需要實(shí)現(xiàn)圖片下載邏輯,于是實(shí)現(xiàn)并注冊(cè)。
[WXSDKEngine registerHandler:[CNCWeexImageLoaderImplement new] withProtocol:@protocol(WXImgLoaderProtocol)];
Module
Module可以理解為JS端需要調(diào)用native才能處理的邏輯,并且在JS<->native進(jìn)行交互。這么說(shuō)有點(diǎn)抽象,舉個(gè)具體的例子:比如在JS端想訪問(wèn)native端的數(shù)據(jù)庫(kù)(coredata、realm等),就需要實(shí)現(xiàn)一個(gè)module來(lái)滿(mǎn)足JS調(diào)用native寫(xiě)好的module以實(shí)現(xiàn)native的邏輯。
在我的實(shí)戰(zhàn)項(xiàng)目中,選擇用module的方式實(shí)現(xiàn)網(wǎng)絡(luò)請(qǐng)求與導(dǎo)航跳轉(zhuǎn)。
[WXSDKEngine registerModule:@"urlRoute" withClass:[CNCWeexURLRouteModule class]];
[WXSDKEngine registerModule:@"networkRequest" withClass:[CNCWeexURLRouteModule class]];
Component
Component很好理解,要實(shí)現(xiàn)一個(gè)跑馬燈UI的效果,在native端實(shí)現(xiàn),并且注冊(cè)到JS。JS端調(diào)用,即可展示出跑馬燈。這就是Component,在JS滿(mǎn)足不了或者實(shí)現(xiàn)成本很高的時(shí)候,則可以在native端實(shí)現(xiàn)Component供JS調(diào)用。
由于第一次試水Weex,并沒(méi)有采取很復(fù)雜的UI,就沒(méi)有用Component。
踩過(guò)的坑
JS中this關(guān)鍵字的用法與Objc不同,this的作用域僅在當(dāng)前對(duì)象。而在JS中函數(shù)也算一個(gè)對(duì)象。如果在函數(shù)中套一個(gè)函數(shù),此時(shí)用this,只能代表外層函數(shù)。而非Objc一樣代表整個(gè)最外層對(duì)象,需要注意!
業(yè)務(wù)中碰到一個(gè)場(chǎng)景,需要在某個(gè)場(chǎng)景,native端主動(dòng)調(diào)用JS。而Weex提供給外部的API并沒(méi)有提供這樣的能力,僅僅是在JS主動(dòng)調(diào)native方法時(shí)傳一個(gè)callback,并且在native方法執(zhí)行完成時(shí),callback銷(xiāo)毀。而業(yè)務(wù)場(chǎng)景卻需要在將來(lái)執(zhí)行回傳下來(lái)的callback。翻看源碼,只能自己實(shí)現(xiàn)了。這里給個(gè)思路:
其實(shí)在Weex的實(shí)現(xiàn)中(不貼源碼了),會(huì)判斷native實(shí)現(xiàn)的方法(即給JS調(diào)用的方法,比如module實(shí)現(xiàn)的方法)的入?yún)㈩?lèi)型。如果是聲明成WXModuleCallback,則Weex內(nèi)部會(huì)進(jìn)行處理,并轉(zhuǎn)成block給iOS(Android同理)。而如果不是WXModuleCallback,則會(huì)透?jìng)饕粋€(gè)String(weex標(biāo)記的方法ID)下來(lái),這很關(guān)鍵。于是我們可以投機(jī)取巧地把入?yún)⒏某蒘tring,記錄下這個(gè)String。在后期想調(diào)這個(gè)JS方法時(shí),寫(xiě)如下代碼即可
[[WXSDKManager bridgeMgr] callBack:weexInstance.instanceId funcId:aliveCallBackID params:params keepAlive:YES];
看法
Weex相比React Native,坑還是比較多的。但是從“使用者”角度來(lái)說(shuō),Weex方便很多。但是對(duì)于存在很多復(fù)雜業(yè)務(wù)場(chǎng)景的開(kāi)發(fā)者來(lái)說(shuō),必然會(huì)去學(xué)習(xí)其原理,而此時(shí)Weex相比RN就沒(méi)那么友善了。
因?yàn)樵诎⒗?,我更加支持Weex,也希望它變得越來(lái)越好。
無(wú)論采用哪種方式,兩者都能實(shí)現(xiàn)客戶(hù)端的動(dòng)態(tài)化。而這對(duì)于一些多變的頁(yè)面來(lái)說(shuō),是一種新的選擇方式。
這是客戶(hù)端動(dòng)態(tài)化系列的第二篇文章,讀者可以看前篇客戶(hù)端動(dòng)態(tài)化系列之——URLRoute,相信你對(duì)動(dòng)態(tài)化有更深的理解。