深刻wepy源碼:wepy運行原理分析

在分析源碼以前,咱們先來回顧一下,wepy 的使用:javascript

<!-- 小程序入口 app.wpy -->
<script> import wepy from 'wepy'; export default class extends wepy.app { ...... } </script>
複製代碼

讓咱們一塊兒看看 export 出來的 class,是怎麼轉換成小程序語言的。java

《深刻wepy源碼:wpy文件編譯過程》中,咱們介紹了 wepy-cli 是如何編譯 wpy 文件的,裏面有說到,complie-script.js 在處理 script 代碼時,會加入 wepy 初始化的代碼。編譯以後 dist 目錄下的文件,以下:c++

// 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 的目錄結構,以便後面的分析更好理解。git

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'] 這些方法。github

還執行了 $initAPI(),主要利用 Object.defineProperty 的 get 方法,將返回封裝爲 promise,這裏也是 API 實現 promise 寫法的核心。npm

$createPage

// dist/pages/index.js 
Page(require('./../npm/wepy/lib/wepy.js').default.$createPage(Index , 'pages/index'));
複製代碼

$createPage()$createApp() 相似,只不過是返回的是 Page 的方法,此外,還在生命週期中,添加了數據髒值檢查 $apply()小程序

數據綁定

wepy 使用髒數據檢查對原生小程序 setData 進行封裝,在函數運行週期結束時執行髒數據檢查。若是在異步函數中更新數據時,則須要手動執行 $apply()。貼一張官方的流程圖。promise

$createPage() 中,會在生命週期中調用 $apply(),來看一下它的定義:bash

$apply (fn) {
  if (typeof(fn) === 'function') {
    fn.call(this);
    this.$apply();
  } else {
    if (this.$$phase) {
      this.$$phase = '$apply';
    } else {
      this.$digest();
    }
  }
}
複製代碼

$$phase 標識是否有 髒數據檢查 在運行,若是沒有,則執行 $digest()app

$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~

相關文章
相關標籤/搜索