TML5課件
玩微信的朋友對(duì)HTML5都不陌生,它就像一個(gè)絕世大美女,一出場(chǎng)就受到了各方的強(qiáng)烈關(guān)注,自然也受到了移動(dòng)學(xué)習(xí)平臺(tái)(m-learning)的青睞。HTML5的資本在于它支持跨平臺(tái),在于它可以實(shí)現(xiàn)文字、圖片、表格、音頻、視頻的有機(jī)結(jié)合,在于它良好的交互性。
支持跨平臺(tái)學(xué)習(xí)
相對(duì)于傳統(tǒng)的HTML技術(shù),HTML5針對(duì)終端設(shè)備增加了許多新特性,只需一個(gè)版本即可實(shí)現(xiàn)跨平臺(tái)、跨分辨率、終端自適應(yīng)等。不需要再考慮是得用電腦還是手機(jī),得用蘋(píng)果還是安卓。不管什么設(shè)備,只需要一個(gè)支持HTML5的瀏覽器,統(tǒng)統(tǒng)搞定。
HTML5的這個(gè)特性對(duì)于移動(dòng)學(xué)習(xí)來(lái)說(shuō)無(wú)疑是個(gè)特大好消息,簡(jiǎn)直就是為了移動(dòng)學(xué)習(xí)量身定做的。如此一來(lái),HTML5課件可以跨平臺(tái),并實(shí)現(xiàn)終端自適應(yīng),既節(jié)省了培訓(xùn)課件開(kāi)發(fā)者的時(shí)間,又能讓學(xué)員獲得良好一致的學(xué)習(xí)體驗(yàn)。
文字、圖片、音頻、視頻等多種呈現(xiàn)方式
Web剛出現(xiàn)的時(shí)候,我們都在網(wǎng)上看些基礎(chǔ)文檔學(xué)習(xí),隨著互聯(lián)網(wǎng)技術(shù)的發(fā)展,純靜態(tài)頁(yè)面已經(jīng)難以吸引用戶(hù)的眼球,而HTML5課件的出現(xiàn),讓人眼前一亮,音頻、視頻等多媒體元素的支持,讓學(xué)習(xí)內(nèi)容變得更加豐富多彩,極大地提升了學(xué)員的學(xué)習(xí)興趣,這在課件形式上也是一場(chǎng)質(zhì)的飛躍。
良好的交互性
上學(xué)的時(shí)候,老師都比較喜歡積極發(fā)言的同學(xué),因?yàn)榛?dòng)。同樣,在開(kāi)發(fā)設(shè)計(jì)網(wǎng)頁(yè)課件時(shí),教學(xué)設(shè)計(jì)人員也希望可以與用戶(hù)互動(dòng)。HTML5的特性,正可以讓教學(xué)設(shè)計(jì)人員設(shè)計(jì)一些學(xué)習(xí)交互點(diǎn),提升學(xué)員的學(xué)習(xí)參與度。
正因?yàn)镠TML5課件有如此多特性,使得企業(yè)在培訓(xùn)的微課形式上,更喜歡HTML5課件。思創(chuàng)擁有16年e-learning綜合服務(wù)經(jīng)驗(yàn),為客戶(hù)提供課程定制開(kāi)發(fā)服務(wù),課件形式包括:快速開(kāi)發(fā)、圖文類(lèi)、綜合動(dòng)畫(huà)、HTML5交互。
更多資訊關(guān)注微信公眾號(hào):思創(chuàng)云學(xué)習(xí)
著各大平臺(tái)小程序的快速放量,開(kāi)發(fā)者遇到越來(lái)越多的平臺(tái)適配問(wèn)題。各平臺(tái)小程序的性能優(yōu)化方法也各不相同,我們?cè)撊绾螒?yīng)對(duì)?DCloud CTO 崔紅保在 GMTC 深圳 2019(全球大前端技術(shù)大會(huì))分享了《小程序的未來(lái)方向》,介紹了小程序技術(shù)架構(gòu)、性能卡點(diǎn)以及各平臺(tái)優(yōu)化方案,對(duì)于小程序未來(lái)的技術(shù)更迭,提出了小程序在未來(lái)可能的發(fā)展方向。本文根據(jù)演講內(nèi)容整理而成。
簡(jiǎn)單介紹一下我自己,中年碼農(nóng),跨平臺(tái)開(kāi)發(fā)領(lǐng)域的老兵。在那個(gè)翻蓋摩托羅拉手機(jī)代表著先進(jìn)和時(shí)髦的年代,我就開(kāi)始參與 “window mobile/j2me/symbain” 等系統(tǒng)的跨平臺(tái)研發(fā)管理工作,可能很多同學(xué)都沒(méi)見(jiàn)過(guò)那些手機(jī)。到后來(lái)的移動(dòng)互聯(lián)網(wǎng)時(shí)代及當(dāng)下的小程序時(shí)代,我也一直在深度參與其中,持續(xù)輸出“Hybrid App”引擎、前端 UI 庫(kù)(mui)及小程序跨端開(kāi)發(fā)框架(uni-app)。目前在 DCloud 任職 CTO,同時(shí)兼 “uni-app” 產(chǎn)品負(fù)責(zé)人。
羅馬不是一天建成的,小程序也不是一天發(fā)明的。小程序這種介于 H5 和 Native App 之間的特殊應(yīng)用形態(tài),從探索到成熟,經(jīng)歷了哪些過(guò)程?我們首先帶大家回顧梳理一下。然后,從現(xiàn)有技術(shù)架構(gòu)出發(fā),分析小程序當(dāng)下幾個(gè)主要性能坑點(diǎn)。各家小程序引擎為解決這些坑點(diǎn),做了哪些完善工作。比如,大家知道小程序是以 Web 渲染為主、原生渲染為輔,那引入原生渲染后,引發(fā)了哪些新的問(wèn)題?為解決這些問(wèn)題,微信提出了同層渲染的方案,同層渲染在技術(shù)層面上又是如何實(shí)現(xiàn)的?最后從當(dāng)前已知問(wèn)題出發(fā),對(duì)于小程序未來(lái)的技術(shù)更迭,拋出一些我們認(rèn)為的可能方向,供大家參考。
HTML5 于 2007 年在 W3C 立項(xiàng),與 iPhone 發(fā)布同年。
喬布斯曾期待 HTML5 能幫助 iPhone 打造起應(yīng)用生態(tài)系統(tǒng)。但 HTML5 的發(fā)展速度并不如預(yù)期,雖然它成功地打破了 IE+Flash 壟斷的局面,卻沒(méi)有達(dá)到承載優(yōu)秀的移動(dòng)互聯(lián)網(wǎng)體驗(yàn)的地步。
蘋(píng)果公司在 iPhone 站穩(wěn)腳跟后,緊接著發(fā)布了自己的 App Store,開(kāi)啟了移動(dòng)互聯(lián)網(wǎng)的原生應(yīng)用時(shí)代。
大家知道現(xiàn)在手機(jī)端主要是 iOS、Android 兩大系統(tǒng),實(shí)際上在早期有 3 大系統(tǒng)競(jìng)爭(zhēng),還有一個(gè)就是諾基亞的 MeeGo 系統(tǒng),MeeGo 采用 C + HTML5 的雙模應(yīng)用生態(tài)策略。然而,C 的開(kāi)發(fā)難度太大,HTML5 體驗(yàn)又不行,所以后來(lái) MeeGo 就掉隊(duì)了;與之對(duì)應(yīng),Android 依靠 Java 技術(shù)生態(tài),在競(jìng)爭(zhēng)中脫穎而出。
于是在移動(dòng)互聯(lián)網(wǎng)初期,應(yīng)用生態(tài)被定了基調(diào) —— 原生開(kāi)發(fā)。
國(guó)內(nèi)有一批做瀏覽器的廠商,嘗試去改進(jìn) HTML5。比如,百度在 2013 年的百度世界大會(huì)上發(fā)布了輕應(yīng)用,通過(guò)給 WebView 擴(kuò)展原生能力,補(bǔ)充 JS API,讓 HTML5 應(yīng)用可以實(shí)現(xiàn)更多功能。
這類(lèi)業(yè)務(wù)發(fā)展的頂峰,是微信在 2015 年初發(fā)布的微信 JS SDK,作為國(guó)內(nèi)事實(shí)上最大的手機(jī)瀏覽器,微信為它的瀏覽器內(nèi)核擴(kuò)充了大量 JS API,讓開(kāi)發(fā)者可以用 JS 調(diào)用微信支付、掃碼等眾多 HTML5 做不到的功能。
不過(guò)這類(lèi)業(yè)務(wù)沒(méi)有取得成功,HTML5 的問(wèn)題不止是功能不足,性能體驗(yàn)是更嚴(yán)重的問(wèn)題。而體驗(yàn)問(wèn)題,不是簡(jiǎn)單地?cái)U(kuò)展 JS 能力能搞定的。
與瀏覽器不同,Hybrid 應(yīng)用是另一個(gè)細(xì)分領(lǐng)域,開(kāi)發(fā)者使用 JS 編寫(xiě)應(yīng)用,為了讓 JS 應(yīng)用更接近原生應(yīng)用的功能體驗(yàn),這個(gè)行業(yè)的從業(yè)者做出了很多嘗試。我們 DCloud 公司是業(yè)內(nèi)主流 Hybrid App 引擎提供方之一,我們提出了改進(jìn) HTML5 的“性能功能”障礙的解決方案 —— 通過(guò)工具、引擎優(yōu)化、開(kāi)發(fā)模式調(diào)整,讓開(kāi)發(fā)者可以通過(guò) JS 寫(xiě)出更接近原生 App 體驗(yàn)的應(yīng)用。
多 WebView 模式,原生接管轉(zhuǎn)場(chǎng)動(dòng)畫(huà)、下拉刷新、Tab 分頁(yè),預(yù)載 WebView……各種優(yōu)化技術(shù)不停迭代,終于讓 Hybrid 應(yīng)用取得了性能體驗(yàn)的突破。
Hybrid 應(yīng)用和輕應(yīng)用、微信 JS SDK 等基于瀏覽器增加方案相比,還有一個(gè)巨大的差別:一個(gè)是 Client/Server,一個(gè)是 Browser/Server。簡(jiǎn)單來(lái)說(shuō),Hybrid 應(yīng)用是 JS 編寫(xiě)的需要安裝的 App,而輕應(yīng)用是在線網(wǎng)頁(yè)。
C/S 的應(yīng)用在每次頁(yè)面加載時(shí),僅需要聯(lián)網(wǎng)獲取 JSON 數(shù)據(jù);而 B/S 應(yīng)用除了 JSON 數(shù)據(jù)外,還需要每次從服務(wù)器加載頁(yè)面 DOM、樣式、邏輯代碼,所以 B/S 應(yīng)用的頁(yè)面加載很慢,體驗(yàn)很差。
可是這樣的 C/S 應(yīng)用雖然體驗(yàn)好,卻失去了 HTML5 的動(dòng)態(tài)性,仍然需要安裝、更新,無(wú)法即點(diǎn)即用、直達(dá)二級(jí)頁(yè)面。
那么 C/S 應(yīng)用的動(dòng)態(tài)性是否可以解決呢?對(duì)此, DCloud 率先提出了“流應(yīng)用”概念,把之前 Hybrid 應(yīng)用里的運(yùn)行于客戶(hù)端的 JS 代碼,先打包發(fā)布到服務(wù)器,制定流式加載協(xié)議,手機(jī)端引擎動(dòng)態(tài)下載這些 JS 代碼到本地,并且為了第一次加載速度更快,實(shí)現(xiàn)了應(yīng)用的邊下載邊運(yùn)行。
就像流媒體的邊下邊播一樣,應(yīng)用也可以實(shí)現(xiàn)邊用邊下。
在這套方案的保障下,終于解決了之前的各種難題:讓 JS 應(yīng)用功能體驗(yàn)達(dá)到原生,并且可即點(diǎn)即用、直達(dá)二級(jí)頁(yè)面。
接著就是微信小程序,最初的名字實(shí)際上是微信應(yīng)用號(hào),之后改名為小程序,2016 年 9 月份內(nèi)測(cè),2017 年 1 月正式發(fā)行,再之后阿里巴巴、手機(jī)廠商聯(lián)盟、百度、,陸續(xù)推出了自己的小程序平臺(tái),小程序時(shí)代滾滾而來(lái)。
2018 年 9 月,微信推出云開(kāi)發(fā),這個(gè)功能我們認(rèn)為是小程序發(fā)展歷史上的一個(gè)重要節(jié)點(diǎn),它可以讓前端工程師從前到后將所有業(yè)務(wù)閉環(huán)實(shí)現(xiàn),減少前后端的溝通成本、人力成本、運(yùn)維成本,屬于開(kāi)發(fā)模式的重大升級(jí)。與之前的前端同學(xué)既可通過(guò) JS/CSS 編寫(xiě)前端 UI,又可通過(guò) “Node.js” 寫(xiě)后端業(yè)務(wù),這種所謂全棧開(kāi)發(fā)模式相比,云開(kāi)發(fā)有更好的優(yōu)勢(shì),因?yàn)榍岸送瑢W(xué)對(duì)于 DB 優(yōu)化、彈性擴(kuò)容、攻擊防護(hù)、災(zāi)備處理等方面還是有經(jīng)驗(yàn)欠缺的,但云開(kāi)發(fā)將這些都封裝好了,真正做到僅專(zhuān)注業(yè)務(wù)實(shí)現(xiàn),其它都委托云廠商服務(wù)。
這是一個(gè)比較通用的小程序架構(gòu),目前幾家小程序架構(gòu)設(shè)計(jì)大致都是這樣的(快應(yīng)用的區(qū)別是視圖層只有原生渲染)。
大家知道小程序是一個(gè)邏輯、視圖層分離的架構(gòu)。
邏輯層就是上圖左上角這塊,小程序中開(kāi)發(fā)的所有頁(yè)面 JS 代碼,最后都會(huì)打包合并到邏輯層,邏輯層除了執(zhí)行開(kāi)發(fā)者的業(yè)務(wù) JS 代碼外,還需處理小程序框架的內(nèi)置邏輯,比如 App 生命周期管理。
視圖層就是上圖右上角這塊,用戶(hù)可見(jiàn)的 UI 效果、可觸發(fā)的交互事件在視圖層完成,視圖層包含 Web 組件、原生組件兩種,也就是小程序是原生 +Web 混合渲染的模式,這塊后面會(huì)詳細(xì)講。
邏輯層最后運(yùn)行在 JS CORE 或 V8 環(huán)境中;JS CORE 既不是 DOM 環(huán)境,也不是 Node 環(huán)境,你是無(wú)法使用 JS 中的 DOM 或 BOM 對(duì)象的,你能調(diào)用的僅僅是 ECMAScript 標(biāo)準(zhǔn)規(guī)范中所給出的方法。
那如果你要發(fā)送網(wǎng)絡(luò)請(qǐng)求怎么辦?window.XMLHttpRequest 是無(wú)法使用的(當(dāng)然即使可以調(diào)用,在 iOS 的 WKWebView 中也存在更嚴(yán)格的跨域限制,會(huì)有問(wèn)題)。這時(shí)候,網(wǎng)絡(luò)請(qǐng)求就需要通過(guò)原生的網(wǎng)絡(luò)模塊來(lái)發(fā)送,JS CORE 和原生之間呢,就需要這個(gè) JS Bridge 來(lái)通訊。
小程序這種架構(gòu),最大的好處是新頁(yè)面加載可以并行,讓頁(yè)面加載更快,且不卡轉(zhuǎn)場(chǎng)動(dòng)畫(huà);但同時(shí)也引發(fā)了部分性能坑點(diǎn),今天主要介紹 3 點(diǎn):
我們從“swipeaction”這個(gè)例子講起,需求是用戶(hù)在列表項(xiàng)上向左滑動(dòng),右側(cè)隱藏的菜單跟隨用戶(hù)手勢(shì)平滑移動(dòng)。
若想在小程序架構(gòu)上實(shí)現(xiàn)流暢的跟手滑動(dòng),是很困難的,為什么?
回顧一下小程序架構(gòu),小程序的運(yùn)行環(huán)境分為邏輯層和視圖層,分別由 2 個(gè)線程管理,小程序在視圖層與邏輯層兩個(gè)線程間提供了數(shù)據(jù)傳輸和事件系統(tǒng)。這樣的分離設(shè)計(jì),帶來(lái)了顯而易見(jiàn)的好處:
環(huán)境隔離,既保證了安全性,同時(shí)也是一種性能提升的手段,邏輯和視圖分離,即使業(yè)務(wù)邏輯計(jì)算非常繁忙,也不會(huì)阻塞渲染和用戶(hù)在視圖層上的交互。
但同時(shí)也帶來(lái)了明顯的壞處:
視圖層(WebView)中不能運(yùn)行 JS,而邏輯層 JS 又無(wú)法直接修改頁(yè)面 DOM,數(shù)據(jù)更新及事件系統(tǒng)只能靠線程間通訊,但跨線程通信的成本極高,特別是需要頻繁通信的場(chǎng)景。
基于這樣的架構(gòu)設(shè)計(jì),我們回到“swipeaction”,分析一次 touchmove 的操作,小程序內(nèi)部的響應(yīng)過(guò)程:
(1)用戶(hù)拖動(dòng)列表項(xiàng),視圖層觸發(fā) touchmove 事件,經(jīng) Native 層中轉(zhuǎn)通知邏輯層(邏輯層、視圖層不是直接通訊的,需 Native 中轉(zhuǎn)),即下圖中的?、?兩步;
(2)邏輯層計(jì)算需移動(dòng)的位置,然后再通過(guò) setData 傳遞位置數(shù)據(jù)到視圖層,中間同樣會(huì)由微信客戶(hù)端(Native)做中轉(zhuǎn),即下圖中的?、?兩步。
實(shí)際上,用戶(hù)滑動(dòng)過(guò)程中,touchmove 的回調(diào)觸發(fā)是非常頻繁的,每次回調(diào)都需要 4 個(gè)步驟的通訊過(guò)程,高頻率回調(diào)導(dǎo)致通訊成本大幅增加,極有可能導(dǎo)致頁(yè)面卡頓或抖動(dòng)。為什么會(huì)卡頓,因?yàn)橥ㄓ嵦^(guò)頻繁,視圖層無(wú)法在 16ms 內(nèi)完成 UI 更新。
為解決這種通訊阻塞的問(wèn)題,各家小程序都在逐步提供對(duì)應(yīng)的解決方案,比如微信的 WXS、支付寶的 SJS、百度的 Filter,但每家小程序支持情況不同,詳細(xì)見(jiàn)下表。
另外,微信的“關(guān)鍵幀動(dòng)畫(huà)”、百度的“animation-view” Lottie 動(dòng)畫(huà),也是為減少頻繁通訊的一種變更方式。
其實(shí),通訊阻塞是業(yè)界普遍存在的一個(gè)問(wèn)題,不止小程序,“React Native”“Weex”等同樣存在通訊阻塞的問(wèn)題。只不過(guò)“React Native”“Weex”的視圖層是原生渲染,而小程序是 Web 渲染。我們下面以“Weex”為例來(lái)說(shuō)明。
大家知道,“Weex”底層使用的 JS-Native Bridge,這個(gè) Bridge 使得 JS 和 Native 之間的通信會(huì)有固定的性能損耗。
繼續(xù)以上述“swipeaction”為例,要實(shí)現(xiàn)列表項(xiàng)菜單的跟手滑動(dòng),大致需經(jīng)如下流程:
(1)在 UI 視圖上綁定 touch 事件(或 pan 事件);
(2)當(dāng)手勢(shì)觸發(fā)時(shí), Native UI 層將手勢(shì)事件通過(guò) Bridge 傳遞給 JS 邏輯層 , 這產(chǎn)生了一次 Native UI 到 JS 邏輯的通信,即下圖中的?、?兩步 ;
(3)JS 邏輯在接收到事件后,根據(jù)手指移動(dòng)的偏移量驅(qū)動(dòng)界面變化,這又會(huì)產(chǎn)生一次 JS 到 Native UI 的通信,即下圖中的?、?兩步。
同樣,手勢(shì)回調(diào)事件觸發(fā)的頻率是非常高的,頻繁的的通信帶來(lái)的時(shí)間成本很可能導(dǎo)致界面無(wú)法在 16ms 中完成繪制,卡頓也就產(chǎn)生了。
“Weex”為解決通訊阻塞,提供了“BindingX”解決方案,這是一種稱(chēng)之為“Expression Binding”的機(jī)制,簡(jiǎn)要介紹一下:
(1)接收手勢(shì)事件的視圖,在移動(dòng)過(guò)程中的偏移量以“x,y”兩個(gè)變量表示;
(2)期望改變(跟隨移動(dòng))的視圖,變化的屬性為“translateX”和“translateY”,對(duì)應(yīng)變化的偏移量以“f(x),f(y)”表達(dá)式表示;
(3)將”交互行為 " 以表達(dá)式的方式描述,并提前預(yù)置到 Native UI 層;
(4)交互觸發(fā)時(shí),Native UI 根據(jù)其內(nèi)置的表達(dá)式解析引擎,去執(zhí)行表達(dá)式,并根據(jù)表達(dá)式執(zhí)行的結(jié)果驅(qū)動(dòng)視圖變換,這個(gè)過(guò)程無(wú)需和 JS 邏輯通訊。
偽代碼 - 摘錄自 Weex 官網(wǎng)
復(fù)制代碼
{ anchor: foo_view.ref // ----> 這是 " 產(chǎn)生手勢(shì)的視圖 " 的引用 props: [ { element: foo_view.ref, // ----> 這是 " 期望改變的視圖 " 的引用 expression: f(x) = x, // ----> 這是具體的表達(dá)式 property: translateX // ----> 這是期望改變的屬性 }, { element: foo_view.ref, expression: f(y) = y, // ----> y 屬性 property: translateY } ]}
“React Native”同樣存在類(lèi)似問(wèn)題,為避免頻繁的通信,“React Native”生態(tài)也有對(duì)應(yīng)方案,比如“Animated”組件及 Lottie 動(dòng)畫(huà)支持。以 “Animated”組件為例,為實(shí)現(xiàn)流暢的動(dòng)畫(huà)效果,該組件采用了聲明式的 API,在 JS 端僅定義了輸入與輸出以及具體的 transform 行為,而真正的動(dòng)畫(huà)是通過(guò) Native Driver 在 Native 層執(zhí)行,這樣就避免了頻繁的通信。然而,聲明式的方式能夠定義的行為有限,無(wú)法勝任交互場(chǎng)景。
“uni-app”在 App 端同樣面臨通訊阻塞的問(wèn)題,我們目前的方案是采用類(lèi)似微信 WXS 的機(jī)制(內(nèi)部叫“renderjs”),但放開(kāi)了 WXS 中無(wú)法獲取頁(yè)面 DOM 元素的限制,比如下圖中多個(gè)小球同時(shí)移動(dòng)的 canvas 動(dòng)畫(huà),“uni-app”在 App 端的實(shí)現(xiàn)方案是:
(1)renderjs 中獲取 canvas 對(duì)象;
(2)基于 web 的 canvas 繪制動(dòng)畫(huà),而非原生 canvas 繪制。
Tips:大家需要注意,并不是所有場(chǎng)景都是原生性能更好,小程序架構(gòu)下,如上多球同時(shí)移動(dòng)的動(dòng)畫(huà),原生 canvas 并不如在 WXS(renderjs)中直接調(diào)用 Web canvas
下表總結(jié)了跨端框架在通訊阻塞方面的解決方案:
小程序架構(gòu)存在通訊阻塞問(wèn)題,廠商為解決這個(gè)問(wèn)題,創(chuàng)造了“WXS”腳本語(yǔ)言及關(guān)鍵幀動(dòng)畫(huà)等方式,但這些都是廠商維度的優(yōu)化方案。我們作為小程序開(kāi)發(fā)者,在性能優(yōu)化方面,又能做哪些工作呢?
小程序開(kāi)發(fā)性能優(yōu)化,核心就是“setData”的調(diào)用,你能做只有兩件事情:
(1)減少 setData 調(diào)用次數(shù)
假設(shè)我們有更改多個(gè)變量值的需求,示例如下:
change:function(){
? ? this.setData({a:1});
? ? ... // 其它業(yè)務(wù)邏輯
? ? this.setData({b:2});
? ? ... // 其它業(yè)務(wù)邏輯
? ? this.setData({c:3});
? ? ... // 其它業(yè)務(wù)邏輯
? ? this.setData({d:4});
}
如上,4 次調(diào)用“setData”,會(huì)引發(fā) 4 次邏輯層、視圖層數(shù)據(jù)通訊。這種場(chǎng)景,開(kāi)發(fā)者需意識(shí)到“setData”有極高的調(diào)用代價(jià),自己需手動(dòng)調(diào)整代碼,合并數(shù)據(jù),減少數(shù)據(jù)通訊次數(shù)。
部分小程序三方框架已內(nèi)置數(shù)據(jù)合并的能力,比如“uni-app”在 Vue runtime 上進(jìn)行了深度定制,開(kāi)發(fā)者無(wú)需關(guān)注“setData”的調(diào)用代價(jià),可放心編寫(xiě)如下代碼:
change:function(){
? ? this.a = 1;
? ? ... // 其它業(yè)務(wù)邏輯
? ? this.b = 2;
? ? ... // 其它業(yè)務(wù)邏輯
? ? this.c = 3;
? ? ... // 其它業(yè)務(wù)邏輯
? ? this.d = 4;
}
如上 4 次賦值,uni-app 運(yùn)行時(shí)會(huì)自動(dòng)合并成“{“a”:1,“b”:2,“c”:3,“d”:4}”一條記錄,調(diào)用一次“setData”完成所有數(shù)據(jù)傳遞,大幅降低 setData 的調(diào)用頻次,結(jié)果如下圖:
減少“setData”調(diào)用次數(shù),還有個(gè)注意點(diǎn):后臺(tái)頁(yè)面(用戶(hù)不可見(jiàn)的頁(yè)面)應(yīng)避免調(diào)用“setData”。
(2)數(shù)據(jù)差量更新
假設(shè)我們有一個(gè) “列表頁(yè) + 上拉加載” 的場(chǎng)景,初始化列表項(xiàng)為 “item1 ~ item4”,用戶(hù)上拉后要向列表追加 4 條新記錄 “item5 ~ item8”,小程序代碼如下:
page({
? ? data:{
? ? ? ? list:['item1','item2','item3','item4']
? ? },
? ? change:function(){
? ? ? ? let newData = ['item5','item6','item7','item8'];
? ? ? ? this.data.list.push(...newData); // 列表項(xiàng)新增記錄
? ? ? ? this.setData({
? ? ? ? ? ? list:this.data.list
? ? ? ? })
? ? }
})
如上代碼,change 方法執(zhí)行時(shí),會(huì)將 list 中的 “item1 ~ item8”8 個(gè)列表項(xiàng)通過(guò)“setData”全部傳輸過(guò)去,而實(shí)際上變化的數(shù)據(jù)只有“item5 ~ item8”。
開(kāi)發(fā)者在這種場(chǎng)景下,應(yīng)通過(guò)差量計(jì)算,僅通過(guò)“setData”傳遞變化的數(shù)據(jù),如下是一個(gè)示例代碼:
page({
? ? data:{
? ? ? ? list:['item1','item2','item3','item4']
? ? },
? ? change:function(){
? ? ? ? // 通過(guò)長(zhǎng)度獲取下一次渲染的索引
? ? ? ? let index = this.data.list.length;
? ? ? ? let newData = ['item5','item6','item7','item8'];
? ? ? ? let newDataObj = {};// 變化的數(shù)據(jù)
? ? ? ? newData.forEach((item) => {
? ? ? ? ? ? newDataObj['list[' + (index++) + ']'] = item;// 通過(guò) list 下標(biāo)精確控制變更內(nèi)容
? ? ? ? });
? ? ? ? this.setData(newDataObj) // 設(shè)置差量數(shù)據(jù)
? ? }
})
每次都手動(dòng)計(jì)算差量變更數(shù)據(jù)是繁瑣的,新手不理解小程序原理的話,也容易忽略這些性能點(diǎn),給 App 埋下性能坑點(diǎn)。
此處,建議開(kāi)發(fā)者選擇成熟的第三方小程序框架,這些框架已經(jīng)自動(dòng)封裝差量數(shù)據(jù)計(jì)算,對(duì)開(kāi)發(fā)者更友好。比如,“uni-app”借鑒了 “westore JSON Diff”庫(kù),在調(diào)用 setData 之前,會(huì)先比對(duì)歷史數(shù)據(jù),精確高效計(jì)算出有變化的差量數(shù)據(jù),然后再調(diào)用 setData,僅傳輸變化的數(shù)據(jù),這樣可實(shí)現(xiàn)傳遞數(shù)據(jù)量的最小化,提升通訊性能。如下,是一個(gè)示例代碼:
export default{
? ? data(){
? ? ? ? return {
? ? ? ? ? ? list:['item1','item2','item3','item4']
? ? ? ? }
? ? },
? ? methods:{
? ? ? ? change:function(){
? ? ? ? ? ? let newData = ['item5','item6','item7','item8'];
? ? ? ? ? ? this.list.push(...newData) // 直接賦值,框架會(huì)自動(dòng)計(jì)算差量數(shù)據(jù)
? ? ? ? }
? ? }
}
Tips:如上 change 方法執(zhí)行時(shí),僅會(huì)將 list 中的 “item5 ~ item8”4 個(gè)新增列表項(xiàng)傳輸過(guò)去,實(shí)現(xiàn)了 setData 傳輸量的極簡(jiǎn)化。
(3)組件差量更新
下圖是一個(gè)微博列表截圖:
假設(shè)當(dāng)前有 200 條微博,用戶(hù)對(duì)某條微博點(diǎn)贊,需實(shí)時(shí)變更其點(diǎn)贊數(shù)據(jù)(狀態(tài));在傳統(tǒng)模式下,一條微博的點(diǎn)贊狀態(tài)變更,會(huì)將整個(gè)頁(yè)面 (Page) 的數(shù)據(jù)全部通過(guò) setData 傳遞過(guò)去,這個(gè)消耗是非常高的;而即使通過(guò)之前介紹,通過(guò)差量計(jì)算的方式獲取變更數(shù)據(jù),這個(gè) Diff 遍歷范圍也很大,計(jì)算效率極低。
如何實(shí)現(xiàn)更高性能的微博點(diǎn)贊?這其實(shí)就是組件更新的典型場(chǎng)景。
合適的方式應(yīng)該是,將每條微博封裝成一個(gè)組件,用戶(hù)點(diǎn)贊后,僅在當(dāng)前組件范圍內(nèi)計(jì)算差量數(shù)據(jù)(可理解為 Diff 范圍縮小為原來(lái)的 1/200),這樣效率才是最高的。
提醒大家注意,并不是所有小程序三方框架都已實(shí)現(xiàn)自定義組件,只有在基于自定義組件模式封裝的框架中,性能才會(huì)大幅提升;如果三方框架是基于老的“template”模板封裝的組件開(kāi)發(fā),則性能并不會(huì)有明顯改善,其 Diff 對(duì)比范圍依然是 Page 頁(yè)面級(jí)的。
大家知道,小程序當(dāng)中有一類(lèi)特殊的內(nèi)置組件——原生組件,這類(lèi)組件有別于 WebView 渲染的內(nèi)置組件,他們是由原生客戶(hù)端渲染的。
小程序中的原生組件,從使用方式上來(lái)說(shuō),主要分為三類(lèi):
除了上面提到的這些之外,其它基本都是 Web 渲染。所以說(shuō),小程序是混合渲染模式,Web 渲染為主,原生渲染為輔。
(1)為什么要引入混合渲染
接下來(lái)的問(wèn)題,為什么要引入原生渲染?以及為什么僅針對(duì)這幾個(gè)組件提供了原生增強(qiáng)?其他組件為什么沒(méi)有做原生實(shí)現(xiàn)?
這就需要我們針對(duì)每個(gè)組件單獨(dú)進(jìn)行分析思考,這里舉了幾個(gè)例子:
提到“input”控件的原生化,可以稍微發(fā)散一下。
小程序中原生 input 控件的通用做法是,未獲取焦點(diǎn)時(shí)以 Web 控件顯示,但在獲取焦點(diǎn)時(shí),繪制一個(gè)原生 input,蓋在 Web input 上方,此時(shí),用戶(hù)看見(jiàn)的鍵盤(pán)即為原生 input 所對(duì)應(yīng)的鍵盤(pán),原生彈出鍵盤(pán)是可自定義按鈕(如上圖中下一步、send 按鈕)。這種做法存在一個(gè)缺陷: Web 和原生,畢竟不同渲染引擎,在鍵盤(pán)彈出和關(guān)閉時(shí),對(duì)應(yīng) input 的“placeholder”會(huì)閃爍。
在 Android 平臺(tái),還有一種做法是基于 WebKit 改造,定制彈出鍵盤(pán)樣式;這種方案,在鍵盤(pán)彈出和關(guān)閉時(shí),input 控件都是 Web 實(shí)現(xiàn)的,故不存在“placeholder”閃爍的問(wèn)題。
(2)混合渲染引發(fā)的問(wèn)題
原生組件雖然帶來(lái)了更豐富的特性及更好的性能,但同時(shí)也引入了一些新的問(wèn)題,比如:
當(dāng)然,并不是所有小程序都存在這種問(wèn)題,部分小程序通過(guò)修改自帶的 WebView 內(nèi)核,實(shí)現(xiàn)了 WebView 也可以使用 rom 主題字體,比如微信、QQ、支付寶;其他小程序(百度、頭條),WebView 仍然無(wú)法渲染為 rom 主題字體。
(3) 混合渲染改進(jìn)方案
既然混合渲染有這些問(wèn)題,對(duì)應(yīng)就會(huì)有解決方案,目前已有的方案如下。
既然其它組件無(wú)法覆蓋到原生組件上,那就創(chuàng)造出一種新的組件,讓這個(gè)新組件可以覆蓋到 video 或 map 上。“cover-view/cover-image”就是基于這種需求創(chuàng)造出來(lái)的新組件;其實(shí)它們也是原生組件,只不過(guò)層級(jí)略高,可以覆蓋在 map、video、canvas、camera 等原生組件上。
目前除了字節(jié)跳動(dòng)外,其它幾家小程序均已支持“cover-view/cover-image”。
cover-view/cover-image 在一定程度上緩解了分層覆蓋的問(wèn)題,但也有部分限制,比如嚴(yán)格的嵌套順序。
既然分層有問(wèn)題,那就消除分層,從 2 層變成 1 層,所有組件都在一個(gè)層中,“z-index”豈不就可生效了?
這個(gè)小目標(biāo)說(shuō)起來(lái)簡(jiǎn)單,具體實(shí)現(xiàn)還是很復(fù)雜的。
拋開(kāi)小程序當(dāng)前架構(gòu)實(shí)現(xiàn),解決混合渲染最直接的方案,應(yīng)該更換渲染引擎,全部基于原生渲染,video/map 和 image/view 均為原生控件,層級(jí)相同,層級(jí)遮蓋問(wèn)題自然消失。這正是“uni-app”在 App 端的推薦方案。
當(dāng)前 Web 渲染為主、原生渲染為輔的主流小程序現(xiàn)狀,如何實(shí)現(xiàn)同層渲染?
基于我們的分析研究,這里簡(jiǎn)單講解一下同層渲染實(shí)現(xiàn)的方案,和微信真實(shí)實(shí)現(xiàn)可能會(huì)有出入(目前僅微信一家實(shí)現(xiàn)了同層渲染)。
(1) iOS 平臺(tái)
小程序在 iOS 端使用 WKWebView 進(jìn)行渲染,WKWebView 在內(nèi)部采用的是分層渲染,一般會(huì)將多個(gè) DOM 節(jié)點(diǎn),合并到一個(gè)層上進(jìn)行渲染。因此,DOM 節(jié)點(diǎn)和層之間不存在一一對(duì)應(yīng)關(guān)系。但是,一旦將一個(gè) DOM 節(jié)點(diǎn)的 CSS 屬性設(shè)置為 “overflow: scroll” 后,WKWebView 便會(huì)為其生成一個(gè) WKChildScrollView,且 WebKit 內(nèi)核已經(jīng)處理了 WKChildScrollView 與其他 DOM 節(jié)點(diǎn)之間的層級(jí)關(guān)系,這時(shí) DOM 節(jié)點(diǎn)就和層之間有一一對(duì)應(yīng)關(guān)系了。
小程序 iOS 端的同層渲染可基于 WKChildScrollView 實(shí)現(xiàn),主要流程如下:
(2)Android 平臺(tái)
小程序在 Android 端采用 Chromium 作為 WebView 渲染層,和 iOS 的 WKWebView 不同,是統(tǒng)一渲染的,不會(huì)分層渲染。但 Chromium 支持 WebPlugin 機(jī)制,WebPlugin 是瀏覽器內(nèi)核的一個(gè)插件機(jī)制,可用來(lái)解析“< embed >”。Android 端的同層渲染可基于 “< embed >”加 Chromium 內(nèi)核擴(kuò)展來(lái)實(shí)現(xiàn),大致流程如下:
這個(gè)流程相當(dāng)于給 WebView 添加了一個(gè)外置插件,且“< embed >”節(jié)點(diǎn)是真正的 DOM 節(jié)點(diǎn),可將更多的樣式作用于該節(jié)點(diǎn)上。
如果要探討小程序接下來(lái)的技術(shù)升級(jí)方向,我們認(rèn)為應(yīng)該在用戶(hù)體驗(yàn)、開(kāi)發(fā)效率兩個(gè)方向上努力。
先說(shuō)用戶(hù)體驗(yàn)的問(wèn)題,主要也是兩個(gè)方面:
如果你也想快速搭建的自己的小程序引擎,并更優(yōu)的解決如上體驗(yàn)問(wèn)題,該怎么辦?
uni-app 發(fā)行到 App 端,實(shí)際上就是一個(gè)完整的小程序引擎,DCloud 會(huì)在近期將這個(gè)引擎完整開(kāi)源,歡迎大家基于 uni-app 小程序 SDK 快速打造自己的小程序平臺(tái)。
uni-app 小程序 SDK 具備如下幾個(gè)特征:
開(kāi)發(fā)效率應(yīng)該從跨端、跨云兩個(gè)維度進(jìn)行分析。
目前的小程序都帶有明顯的廠家屬性,每個(gè)廠家各不相同。比如,阿里內(nèi)部有多套小程序(支付寶、淘寶、釘釘?shù)龋液冒⒗飪?nèi)部目前已基本統(tǒng)一。但騰訊體系下,微信和 QQ 小程序依然是兩隊(duì)人馬,兩套規(guī)范。
小程序之前是手機(jī)端的,2019 年 360 出了 PC 端小程序。
接下來(lái),會(huì)不會(huì)還有其它廠家推出自己的小程序?會(huì)不會(huì)有新的端的出現(xiàn)?比如,面向電視的小程序、面向車(chē)載的小程序?
一切皆有可能。
逐水草而居是人類(lèi)的本能,追求流量依然是互聯(lián)網(wǎng)的制勝法寶。當(dāng)前的小程序宿主,都是億級(jí)流量入口,且各家流量政策不同。比如,微信的流量雖然很大,但有各種限制;百度和頭條是支持廣告投放的,通過(guò)廣告投放,可以快速獲得大量較為精準(zhǔn)的用戶(hù);百度小程序還有個(gè) Web 化的功能,可以將 Web 的搜索流量,轉(zhuǎn)化成小程序的流量。
面對(duì)眾多小程序平臺(tái)及各自巨大的入口流量,開(kāi)發(fā)者如何應(yīng)對(duì)?
等待 W3C 的小程序標(biāo)準(zhǔn)統(tǒng)一,短期不太現(xiàn)實(shí)。當(dāng)下,若想將業(yè)務(wù)快速觸達(dá)多家小程序,借助跨端框架應(yīng)該是唯一可行的方案。
開(kāi)發(fā)商借助“uni-app”或其它跨端框架,雖然已可以開(kāi)發(fā)所有前端應(yīng)用。但仍然需要雇傭 PHP 或 Java 等后臺(tái)開(kāi)發(fā)人員,既有后端人員成本,又有前 / 后端溝通成本。
騰訊、阿里、百度小程序雖陸續(xù)上線了云開(kāi)發(fā),但它們均只支持自己的小程序,無(wú)法跨端,分散的服務(wù)器對(duì)開(kāi)發(fā)商更不可取。
故我們認(rèn)為跨廠商的 Serverless 是接下來(lái)的一個(gè)重點(diǎn)需求,開(kāi)發(fā)者在一個(gè)云端存儲(chǔ)所有業(yè)務(wù)數(shù)據(jù)及后端邏輯,然后將前端小程序發(fā)行到各家小程序平臺(tái),也就是“一云多端”模式。
基于小程序的現(xiàn)狀,我們也許可以總結(jié)一下小程序技術(shù)上的可能方向:
作者介紹:
崔紅保,DCloud CTO,Uni-App 團(tuán)隊(duì)負(fù)責(zé)人,開(kāi)發(fā)了 2 個(gè) Github Star 上萬(wàn)的流行項(xiàng)目。有 10 年以上研發(fā)管理經(jīng)驗(yàn),在跨平臺(tái)引擎、前端 UI、小程序性能優(yōu)化等方面有豐富的實(shí)踐經(jīng)驗(yàn)。
著小程序正式對(duì)外發(fā)布之即,微信團(tuán)隊(duì)近日北京舉辦了一場(chǎng)線下公開(kāi)課,筆者也應(yīng)邀參加了這次公開(kāi)課的分享,微信團(tuán)隊(duì)在公開(kāi)課里透漏的,有很多細(xì)節(jié)筆者在之前的一篇文章《小程序來(lái)了,這些細(xì)節(jié)你必須注意!》都有提及過(guò),但是通過(guò)這次與微信團(tuán)隊(duì)的直接接觸,我把內(nèi)容整理出來(lái),讓吃瓜群眾對(duì)小程序有一個(gè)更加清晰的認(rèn)識(shí),本篇文章圖片較多,建議在WIFI環(huán)境下閱讀。
第一部分:小程序接入流程,吃瓜群眾務(wù)必知曉
第二部分:運(yùn)營(yíng)規(guī)范,設(shè)計(jì)人員必須了解
第三部分:框架解析,技術(shù)黨務(wù)必理解
第四部分:實(shí)戰(zhàn)分享,開(kāi)發(fā)者最渴望的實(shí)戰(zhàn)經(jīng)驗(yàn)
第五部分:小程序不是HTML5
微信團(tuán)隊(duì)在本次公開(kāi)課中明確提出“小程序不是HTML5”,其實(shí)說(shuō)到這里我們可以這樣分別定義小程序和HTML5,以小程序?yàn)榇淼?hybrid app 和以 HTML 5 為代表的 web app。“小程序”在騰訊內(nèi)部被統(tǒng)一稱(chēng)為 web+,Web+ 是什么?可以簡(jiǎn)單理解為一種“混搭”的開(kāi)發(fā)方式或是具備 Native 能力的 web 應(yīng)用框架。它既不是純粹的 web 開(kāi)發(fā),也不是 ios 或是 Android 開(kāi)發(fā),它是 MIX 的,雖然像 web 一樣更輕,但也像 Native 應(yīng)用開(kāi)發(fā)一樣更加重視用戶(hù)體驗(yàn)本身。
關(guān)于小程序更多的開(kāi)發(fā)、運(yùn)營(yíng)、設(shè)計(jì)的解讀,大家可以查閱筆者早前發(fā)表的一篇文章《小程序來(lái)了,這些細(xì)節(jié)你必須注意!》 去詳細(xì)學(xué)習(xí)。
第六部分:小程序經(jīng)典案例解讀
本次公開(kāi)課微信團(tuán)隊(duì)除了分享有關(guān)開(kāi)發(fā)層面的實(shí)戰(zhàn)分享之外,還特例拿出了1-2個(gè)小程序作為經(jīng)典案例進(jìn)行分享。
在本次小程序公開(kāi)課后的分享中,微信團(tuán)隊(duì)特別提到到了一個(gè)標(biāo)桿性的小程序—自選股,筆者在課后也了解到了這只開(kāi)發(fā)團(tuán)隊(duì)的相關(guān)情況,根據(jù)了解,這只團(tuán)隊(duì)是騰訊內(nèi)部最早進(jìn)入微信小程序內(nèi)測(cè)的6個(gè)團(tuán)隊(duì)的其中之一。
自選股團(tuán)隊(duì)負(fù)責(zé)人強(qiáng)調(diào)它們的小程序是一款基于微信體系小而美額度產(chǎn)品,去掉了APP里像研報(bào)、投資評(píng)級(jí)、機(jī)構(gòu)評(píng)級(jí)以及公司財(cái)報(bào)等功能,同時(shí)結(jié)合微信的社交屬性,在用戶(hù)與微信好友在聊天時(shí),就能夠通過(guò)自選股小程序了解當(dāng)前的股市行情,這類(lèi)產(chǎn)品就很好的響應(yīng)了小程序"更小、更輕"的理念。
從效率上來(lái)說(shuō),小程序產(chǎn)品在微信Web+框架下的開(kāi)發(fā)速度是遠(yuǎn)比原生應(yīng)用更快,跨平臺(tái)的適配性更高,開(kāi)發(fā)成本更低。以騰訊自選股小程序?yàn)槔?個(gè)人的團(tuán)隊(duì)在5天內(nèi)就開(kāi)發(fā)完成了整個(gè)小程序。
同時(shí),微信自選股團(tuán)隊(duì)負(fù)責(zé)人還透漏了一個(gè)細(xì)節(jié),小程序能夠支持股票移動(dòng)的動(dòng)態(tài)顯示,讓股民能夠更直觀的看到股票的變化,微信小程序已經(jīng)支持整個(gè) CSS3 的動(dòng)畫(huà),而這在 Native 的股票 App 中,也不是所有的都能做到這一點(diǎn)。
這是一個(gè)典型的符合小程序設(shè)計(jì)理念的產(chǎn)品,正如微信團(tuán)隊(duì)在官方設(shè)計(jì)規(guī)范中所提及的“產(chǎn)品設(shè)計(jì)遵循重點(diǎn)突出”。
開(kāi)發(fā)速度加快,必然的帶來(lái)了開(kāi)發(fā)成本的降低,效率因此獲得提高。不過(guò),開(kāi)發(fā)者當(dāng)對(duì)市場(chǎng)情況和用戶(hù)需求并不十分確定的情況下,它讓快速、低成本的試錯(cuò)成為可能。
第七部分:微信公開(kāi)課給了我們更明確的信號(hào)
小程序的設(shè)計(jì)完全可以對(duì)標(biāo)第三方服務(wù)里的小應(yīng)用
在小程序推出之前,我們大家所熟知的微信第三方服務(wù)所包含的應(yīng)用其實(shí)都可以看做是小程序的縮影,筆者對(duì)比了幾個(gè)典型的應(yīng)用,我們完全可以看出小程序所有細(xì)節(jié),統(tǒng)一的Title標(biāo)題和Background背景,統(tǒng)一的Tab格局,統(tǒng)一的按鈕尺寸和色塊,這些細(xì)節(jié)和小程序定義的規(guī)范極其接近。
小程序就是要突出重點(diǎn),快速直達(dá)用戶(hù)的需求
小程序“自選股”把AP的重點(diǎn)功能“實(shí)時(shí)行情”放到了小程序里,并且做到了用戶(hù)極致體驗(yàn);同城旅游把重點(diǎn)功能票務(wù)預(yù)訂放到了小程序里;藝龍旅行網(wǎng)把重點(diǎn)功能“酒店預(yù)訂”放到了小程序里;大眾點(diǎn)評(píng)把重點(diǎn)功能外賣(mài)放到了小程序里,通過(guò)以上案例我們不難看出,這些開(kāi)發(fā)者只是把AP的其中一項(xiàng)功能或者單個(gè)頁(yè)面搬到了小程序上,拋棄了除主需求之外所有的陪襯功能,以最直接的方式滿足用戶(hù)的需求。如果我們把APP定位成一頓滿足胃口的大餐,那小程序就是快速解決溫飽問(wèn)題一頓快餐了。但是人在餓的時(shí)候,一頓快餐的解決問(wèn)題的快感顯然要比一頓大餐好的多。
第八部分、微信團(tuán)隊(duì)正在逐步推進(jìn)小程序的進(jìn)程
我在小程序公測(cè)之后的一篇文章《小程序來(lái)了,這些細(xì)節(jié)你必須注意!》里有提到過(guò)這樣一個(gè)觀點(diǎn),小程序箭在弦上卻不能發(fā)布是因?yàn)槲⑿艌F(tuán)隊(duì)剛剛公布公測(cè)消息,市場(chǎng)的反饋需要一定的時(shí)間,微信團(tuán)隊(duì)還沒(méi)有給市場(chǎng)一個(gè)可以借鑒的標(biāo)桿。通過(guò)微信團(tuán)隊(duì)這次的公開(kāi)課和前段時(shí)間張小龍爆出的手機(jī)截圖顯示,僅僅過(guò)去20多天,微信團(tuán)隊(duì)似乎已經(jīng)找到了不下20個(gè)可以稱(chēng)得上標(biāo)桿的小程序。微信團(tuán)隊(duì)通過(guò)這次公開(kāi)課就是想再次給市場(chǎng)傳遞一個(gè)信號(hào):什么可以做,什么不能做,應(yīng)該怎么做。看到市場(chǎng)上這么多想擁抱小程序的開(kāi)發(fā)者,筆者想說(shuō)的是,其實(shí)最急的不是你們,而是微信團(tuán)隊(duì)。它們迫切的希望您們?nèi)肀В顦?lè)意看到的現(xiàn)狀就是,它們所制定的生態(tài)規(guī)則能夠在最短的時(shí)間內(nèi)被市場(chǎng)所接受,并且開(kāi)發(fā)者上手的速度越快越好,從而幫助微信團(tuán)隊(duì)更好的打造這個(gè)偉大的生態(tài)系統(tǒng)。
【作者:春曉。公眾號(hào):wsbang520。個(gè)人ID:cxfdaiyi001,歡迎經(jīng)驗(yàn)交流。】
*請(qǐng)認(rèn)真填寫(xiě)需求信息,我們會(huì)在24小時(shí)內(nèi)與您取得聯(lián)系。