在分析原始碼之前,我們先來回顧一下,wepy 的使用:
<!-- 小程式入口 app.wpy -->
<script>
import wepy from 'wepy';
export default class extends wepy.app {
......
}
</script>
複製程式碼
讓我們一起看看 export 出來的 class,是怎麼轉換成小程式語言的。
在《深入wepy原始碼:wpy檔案編譯過程》中,我們介紹了 wepy-cli 是如何編譯 wpy 檔案的,裡面有說到,complie-script.js 在處理 script 程式碼時,會加入 wepy 初始化的程式碼。編譯之後 dist 目錄下的檔案,如下:
// dist/app.js
App(require('./npm/wepy/lib/wepy.js').default.$createApp(_default, {}));
// dist/pages/index.js
Page(require('./../npm/wepy/lib/wepy.js').default.$createPage(Index , 'pages/index'));
複製程式碼
可以看出,主要呼叫了 $createApp
和 $createPage
方法。在看這兩個方法之前,我們先來看一下 wepy 的目錄結構,以便後面的分析更好理解。
wepy目錄結構
├─wepy
├─src
├─app.js 全域性app邏輯,請求優化、promisify API、攔截器功能等
├─base.js 定義了 $createApp 和 $createPage 等方法
├─component.js 元件邏輯,髒值檢查、元件通訊等
├─event.js 事件方法
├─mixin.js 混合方法
├─native.js 空,程式碼裡用於app.js中重新定義wx介面
├─page.js 繼承component,page的一些優化
├─util.js 工具方法
├─wepy.js 入口檔案
├─test
├─...
複製程式碼
$createApp
和 $createPage
$createApp
// dist/app.js
App(require('./npm/wepy/lib/wepy.js').default.$createApp(_default, {}));
複製程式碼
$createApp()
返回了一個型別為 object 的 config,裡面包含了 ['onLaunch', 'onShow', 'onHide', 'onError']
這些方法。
還執行了 $initAPI()
,主要利用 Object.defineProperty
的 get 方法,將返回封裝為 promise,這裡也是 API 實現 promise 寫法的核心。
$createPage
// dist/pages/index.js
Page(require('./../npm/wepy/lib/wepy.js').default.$createPage(Index , 'pages/index'));
複製程式碼
$createPage()
和 $createApp()
類似,只不過是返回的是 Page 的方法,此外,還在生命週期中,新增了資料髒值檢查 $apply()
。
資料繫結
wepy 使用髒資料檢查對原生小程式 setData
進行封裝,在函式執行週期結束時執行髒資料檢查。如果在非同步函式中更新資料時,則需要手動執行 $apply()
。貼一張官方的流程圖。
在 $createPage()
中,會在生命週期中呼叫 $apply()
,來看一下它的定義:
$apply (fn) {
if (typeof(fn) === 'function') {
fn.call(this);
this.$apply();
} else {
if (this.$$phase) {
this.$$phase = '$apply';
} else {
this.$digest();
}
}
}
複製程式碼
$$phase
標識是否有 髒資料檢查 在執行,如果沒有,則執行 $digest()
。
$digest() {
let k;
let originData = this.$data;
this.$$phase = '$digest';
this.$$dc = 0;
while (this.$$phase) {
this.$$dc++;
if (this.$$dc >= 3) {
throw new Error('Can not call $apply in $apply process');
}
......
this.$$phase = (this.$$phase === '$apply') ? '$digest' : false;
}
}
複製程式碼
$digest()
執行時,主要是遍歷 originData
,將 originData[k]
和 this[k]
做對比,如果不一樣,放到 readyToSet
中,在迴圈之後,統一執行 setData
方法。
最後,在檢查 $$phase 是否有被設定為 '$apply'
,如果是,則再做一次髒資料檢查。
最後
本文分析的原始碼以 wepy@1.7.1 版本為準,更多資訊可參考 wepy github (即 github 1.7.x 分支)。另外,文中有任何表述不清或不當的地方,歡迎大家批評指正。
本文首發於:github.com/yingye/Blog…
歡迎各位關注我的Blog,正文以issue形式呈現,喜歡請點star,訂閱請點watch~