深刻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~

相关文章
相关标签/搜索