小程序是一種全新的鏈接用戶與服務的方式,它能夠在微信內被便捷地獲取和傳播,同時具備出色的使用體驗。css
小程序並不是憑空冒出來的一個概念。當微信中的 WebView 逐漸成爲移動 Web 的一個重要入口時,微信就有相關的 JS API 了。html
代碼清單1-1 使用 WeixinJSBridge 預覽圖片前端
WeixinJSBridge.invoke('imagePreview', { current: 'http://inews.gtimg.com/newsapp_bt/0/1693121381/641', urls: [ // 全部圖片的URL列表,數組格式 'https://img1.gtimg.com/10/1048/104857/10485731_980x1200_0.jpg', 'https://img1.gtimg.com/10/1048/104857/10485726_980x1200_0.jpg', 'https://img1.gtimg.com/10/1048/104857/10485729_980x1200_0.jpg' ] }, function(res) { console.log(res.err_msg) })
代碼1-1是一個調用微信原生組件瀏覽圖片的JS API,相比於額外引入一個JS圖片預覽組件庫,這種調用方式顯得很是簡潔和高效。canvas
實際上,微信官方是沒有對外暴露過如此調用的,此類 API 最初是提供給騰訊內部一些業務使用,不少外部開發者發現了以後,依葫蘆畫瓢地使用了,逐漸成爲微信中網頁的事實標準。2015年初,微信發佈了一整套網頁開發工具包,稱之爲 JS-SDK,開放了拍攝、錄音、語音識別、二維碼、地圖、支付、分享、卡券等幾十個API。給全部的 Web 開發者打開了一扇全新的窗戶,讓全部開發者均可以使用到微信的原生能力,去完成一些以前作不到或者難以作到的事情。小程序
一樣是調用原生的瀏覽圖片,調用方式如代碼清單1-2所示。微信小程序
代碼清單1-2 使用 JS-SDK 調用圖片預覽組件api
wx.previewImage({ current: 'https://img1.gtimg.com/10/1048/104857/10485726_980x1200_0.jpg', urls: [ // 全部圖片的URL列表,數組格式 'https://img1.gtimg.com/10/1048/104857/10485731_980x1200_0.jpg', 'https://img1.gtimg.com/10/1048/104857/10485726_980x1200_0.jpg', 'https://img1.gtimg.com/10/1048/104857/10485729_980x1200_0.jpg' ], success: function(res) { console.log(res) } })
JS-SDK是對以前的 WeixinJSBridge 的一個包裝,以及新能力的釋放,而且由對內開放轉爲了對全部開發者開放,在很短的時間內得到了極大的關注。從數據監控來看,絕大部分在微信內傳播的移動網頁都使用到了相關的接口。數組
JS-SDK 解決了移動網頁能力不足的問題,經過暴露微信的接口使得 Web 開發者可以擁有更多的能力,然而在更多的能力以外,JS-SDK 的模式並無解決使用移動網頁遇到的體驗不良的問題。用戶在訪問網頁的時候,在瀏覽器開始顯示以前都會有一個白屏的過程,在移動端,受限於設備性能和網絡速度,白屏會更加明顯。咱們團隊把不少技術精力放置在如何幫助平臺上的Web開發者解決這個問題。所以咱們設計了一個 JS-SDK 的加強版本,其中有一個重要的功能,稱之爲「微信 Web 資源離線存儲」。瀏覽器
如下文字引用自內部的文檔(沒有最終對外開放):緩存
微信 Web 資源離線存儲是面向 Web 開發者提供的基於微信內的 Web 加速方案。經過使用微信離線存儲,Web 開發者可藉助微信提供的資源存儲能力,直接從微信本地加載 Web 資源而不須要再從服務端拉取,從而減小網頁加載時間,爲微信用戶提供更優質的網頁瀏覽體驗。每一個公衆號下全部 Web App 累計最多可緩存 5M 的資源。
這個設計有點相似 HTML5 的 Application Cache,但在設計上規避了一些 Application Cache的不足。
在內部測試中,咱們發現 離線存儲 可以解決一些問題,但對於一些複雜的頁面依然會有白屏問題,例如頁面加載了大量的 CSS 或者是 JavaScript 文件。除了白屏,影響 Web 體驗的問題還有缺乏操做的反饋,主要表如今兩個方面:頁面切換的生硬和點擊的遲滯感。
微信面臨的問題是如何設計一個比較好的系統,使得全部開發者在微信中都能得到比較好的體驗。這個問題是以前的 JS-SDK 所處理不了的,須要一個全新的系統來完成,它須要使得全部的開發者都能作到:
- 快速的加載
- 更強大的能力
- 原生的體驗
- 易用且安全的微信數據開放
- 高效和簡單的開發
這就是小程序的由來。
微信小程序的框架包含兩部分View視圖層(可能存在多個)、App Service邏輯層(一個),View層用來渲染頁面結構,AppService層用來邏輯處理、數據請求、接口調用,它們在兩個線程裏運行。
視圖層使用WebView渲染,邏輯層使用JSCore運行。
視圖層和邏輯層經過系統層的WeixinJsBridage進行通訊,邏輯層把數據變化通知到視圖層,觸發視圖層頁面更新,視圖層把觸發的事件通知到邏輯層進行業務處理。
重點講一下wxs :
因爲view 與 App Service是不一樣線程,以前是傳遞數據,當遇到一些數據須要在view中處理時,就能夠用wxs來處理,以下所示定義<wxs module="tools">,使用說明
index.js
//獲取應用實例 const app = getApp() Page({ data: { motto: 'Hello World', userInfo: {}, hasUserInfo: false }, //事件處理函數 bindViewTap: function() { }, onLoad: function() { } })
<!--index.wxml--> <view class="container"> <view class="usermotto"> <text class="user-motto">{{tools.bar(motto)}}</text> <text class="user-motto">{{tools.foo}}</text> </view> <wxs module="tools"> var foo = "'hello world' from comm.wxs"; var bar = function(d) { return '啥子玩意'+d; } module.exports = { foo: foo, bar: bar }; </wxs> </view>
小程序啓動會有兩種狀況,一種是「冷啓動」,一種是「熱啓動」。 假如用戶已經打開過某小程序,而後在必定時間內再次打開該小程序,此時無需從新啓動,只需將後臺態的小程序切換到前臺,這個過程就是熱啓動;冷啓動指的是用戶首次打開或小程序被微信主動銷燬後再次打開的狀況,此時小程序須要從新加載啓動。
小程序冷啓動時若是發現有新版本,將會異步下載新版本的代碼包,並同時用客戶端本地的包進行啓動,即新版本的小程序須要等下一次冷啓動纔會應用上。若是須要立刻應用最新版本,可使用 wx.getUpdateManager API 進行處理。
視圖層由 WXML 與 WXSS 編寫,由組件來進行展現。
將邏輯層的數據反應成視圖,同時將視圖層的事件發送給邏輯層。
一、View - WXML
wxml編譯器:wcc 把wxml文件 轉爲 js 執行方式:wcc index.wxml
二、View - WXSS
三、View - Component
四、View - Native Component
每次小程序進入除了當前頁面,Native預先額外加載一個WebView
當打開指定頁面時,用默認數據直接渲染,請求數據回來時局部更新
返回顯示歷史View
退出小程序,View狀態不銷燬
邏輯層將數據進行處理後發送給視圖層,同時接受視圖層的事件反饋
一、App( ) 小程序的入口;Page( ) 頁面的入口
三、提供豐富的 API,如微信用戶數據,掃一掃,支付等微信特有能力。
四、每一個頁面有獨立的做用域,並提供模塊化能力。
五、數據綁定、事件分發、生命週期管理、路由管理
一、App Service - Binding
二、App Service - Life Cylce
三、App Service - API
API經過WeixinJSBridge和Native 進行通訊
四、App Service - Router
保留當前頁面,跳轉到應用內的某個頁面,使用navigateBack能夠返回到原頁面。頁面路徑只能是五層
關閉當前頁面,跳轉到應用內的某個頁面。
關閉當前頁面,返回上一頁面或多級頁面。可經過 getCurrentPages()) 獲取當前的頁面棧,決定須要返回幾層。
5、小程序開發經驗
一、小程序存在的問題
小程序仍然使用WebView渲染,並不是原生渲染
須要獨立開發,不能在非微信環境運行 。
開發者不能夠擴展新組件。
依賴瀏覽器環境的js庫不能使用,由於是JSCore執行的,沒有window、document對象。
WXSS中沒法使用本地(圖片、字體等)。
WXSS轉化成js 而不是css。
WXSS不支持級聯選擇器。
小程序沒法打開頁面,沒法拉起APP。
二、小程序的優勢
提早新建WebView,準備新頁面渲染。
View層和邏輯層分離,經過數據驅動,不直接操做DOM。
使用Virtual DOM,進行局部更新。
所有使用https,確保傳輸中安全。
加入rpx單位,隔離設備尺寸,方便開發。
rpx(responsive pixel): 能夠根據屏幕寬度進行自適應。規定屏幕寬爲750rpx。 如在 iPhone6 上,屏幕寬度爲375px,共有750個物理像素,則750rpx = 375px = 750物理像素, 1rpx = 0.5px = 1物理像素。 設備 rpx換算px (屏幕寬度/750) px換算rpx (750/屏幕寬度) iPhone5 1rpx = 0.42px 1px = 2.34rpx iPhone6 1rpx = 0.5px 1px = 2rpx iPhone6Plus 1rpx = 0.552px 1px = 1.81rpx複製代碼
運行時,外面包裹define,代碼做爲回到,當調用回調時,只傳入前面三個值,因爲後面的變量都是局部定義的變量,就屏蔽了(window,document等這些變量.
其中O就是上面define('app.js',callback),的回調,回調值傳入了三個參數,屏蔽了其餘屬性
小程序的視圖層目前使用 WebView 做爲渲染載體,而邏輯層是由獨立的 JavascriptCore 做爲運行環境。在架構上,WebView 和 JavascriptCore 都是獨立的模塊,並不具有數據直接共享的通道。當前,視圖層和邏輯層的數據傳輸,實際上經過兩邊提供的 evaluateJavascript
所實現。即用戶傳輸的數據,須要將其轉換爲字符串形式傳遞,同時把轉換後的數據內容拼接成一份 JS 腳本,再經過執行 JS 腳本的形式傳遞到兩邊獨立環境。
而 evaluateJavascript
的執行會受不少方面的影響,數據到達視圖層並非實時的。
常見的 setData 操做錯誤
1. 頻繁的去 setData
在咱們分析過的一些案例裏,部分小程序會很是頻繁(毫秒級)的去setData
,其致使了兩個後果:
2. 每次 setData 都傳遞大量新數據
由setData
的底層實現可知,咱們的數據傳輸實際是一次 evaluateJavascript
腳本過程,當數據量過大時會增長腳本的編譯執行時間,佔用 WebView JS 線程,
3. 後臺態頁面進行 setData
當頁面進入後臺態(用戶不可見),不該該繼續去進行setData
,後臺態頁面的渲染用戶是沒法感覺的,另外後臺態頁面去setData
也會搶佔前臺頁面的執行。
圖片資源
開發者在實現業務邏輯同時也有必要儘可能減小代碼包的大小,由於代碼包大小直接影響到下載速度,從而影響用戶的首次打開體驗。除了代碼自身的重構優化外,還能夠從這兩方面着手優化代碼大小:
目前小程序打包是會將工程下全部文件都打入代碼包內,也就是說,這些沒有被實際使用到的庫文件和資源也會被打入到代碼包裏,從而影響到總體代碼包的大小。
小程序在啓動時,會直接加載全部頁面邏輯代碼進內存,即使 page2 可能都不會被使用。在 page1 跳轉至 page2 時,page1 的邏輯代碼 Javascript 數據也不會從內存中消失。page2 甚至能夠直接訪問 page1 中的數據。
小程序的這種機制差別正好能夠更好的實現預加載。一般狀況下,咱們習慣將數據拉取寫在 onLoad 事件中。可是小程序的 page1 跳轉到 page2,到 page2 的 onLoad 是存在一個 300ms ~ 400ms 的延時的。以下圖:
由於小程序的特性,徹底能夠在 page1 中預先拿取數據,而後在 page2 中直接使用數據,這樣就能夠避開 redirecting 的 300ms ~ 400ms了。以下圖:
渲染view線程和AppServcie是相互獨立的,對於AppServcie中js運行不會阻塞view的渲染
官方的示例也是採用這種方式: 先App中請求數據,在index.js使用數據
小程序的主要開發語言是 JavaScript ,小程序的開發同普通的網頁開發相比有很大的類似性。對於前端開發者而言,從網頁開發遷移到小程序的開發成本並不高,可是兩者仍是有些許區別的。
網頁開發渲染線程和腳本線程是互斥的,這也是爲何長時間的腳本運行可能會致使頁面失去響應,而在小程序中,兩者是分開的,分別運行在不一樣的線程中。網頁開發者可使用到各類瀏覽器暴露出來的 DOM API,進行 DOM 選中和操做。而如上文所述,小程序的邏輯層和渲染層是分開的,邏輯層運行在 JSCore 中,並無一個完整瀏覽器對象,於是缺乏相關的DOM API和BOM API。這一區別致使了前端開發很是熟悉的一些庫,例如 jQuery、 Zepto 等,在小程序中是沒法運行的。同時 JSCore 的環境同 NodeJS 環境也是不盡相同,因此一些 NPM 的包在小程序中也是沒法運行的。
網頁開發者須要面對的環境是各式各樣的瀏覽器,PC 端須要面對 IE、Chrome、QQ瀏覽器等,在移動端須要面對Safari、Chrome以及 iOS、Android 系統中的各式 WebView 。而小程序開發過程當中須要面對的是兩大操做系統 iOS 和 Android 的微信客戶端,以及用於輔助開發的小程序開發者工具,小程序中三大運行環境也是有所區別的,如表1-1所示。
表1-1 小程序的運行環境
運行環境 | 邏輯層 | 渲染層 |
---|---|---|
iOS | JavaScriptCore | WKWebView |
安卓 | V8 | chromium定製內核 |
小程序開發者工具 | NWJS | Chrome WebView |
網頁開發者在開發網頁的時候,只須要使用到瀏覽器,而且搭配上一些輔助工具或者編輯器便可。小程序的開發則有所不一樣,須要通過申請小程序賬號、安裝小程序開發者工具、配置項目等等過程方可完成。