加载 JSBundle

一、Native

每一个页面都是一个 instance,framework 是全局唯一的,js 和 native 交互,第一个参数都是 instanceID,依靠 instanceID 来去区分不同的页面直接的调用。

在 controller 中创建 instance

_instance = [[WXSDKInstance alloc] init];
1、renderURL

以 iOS 为例:每一个 controller 都持有一个 WXSDKInstance,加载到 JSBundle 代码后,客户端通过 renderURL 的方式来进行加载。

[_instance renderWithURL:[NSURL URLWithString:randomURL] options:@{@"bundleUrl":URL.absoluteString} data:nil];

WXSDKInstance 在初始化方法里面生成 一个 唯一 instanceID,这个 instanceID 就是和 js 交互时 第一个参数,
在 Weex 架构里面,每一个页面都是一个 instance,通过 instanceID 来区分不同的页面。

renderWithURL
    WXResourceRequest *request = [WXResourceRequest requestWithURL:url resourceType:WXResourceTypeMainBundle referrer:@"" cachePolicy:NSURLRequestUseProtocolCachePolicy];
    [self _renderWithRequest:request options:options data:data];

renderWithURL 生成 request 去加载 jsBundle,里面会判断是否是 本地 file 还是需要从服务器下载,下载成功后调用
- (void)_renderWithMainBundleString:(NSString *)mainBundleString

_renderWithMainBundleString
    WXPerformBlockOnMainThread(^{
        _rootView = [[WXRootView alloc] initWithFrame:self.frame];
        _rootView.instance = self;
        if(self.onCreate) {
            self.onCreate(_rootView);
        }
    });
    // ensure default modules/components/handlers are ready before create instance
    [WXSDKEngine registerDefaults];

    [self _handleConfigCenter];

    [[WXSDKManager bridgeMgr] createInstance:self.instanceId template:mainBundleString options:dictionary data:_jsData];
  1. create WXRootView 作为 instance 的跟 view
  2. 确保 components,module 注册。
  3. 是否需要替换 使用 CoreText 和 Slider
  4. 调用 js 的 createInstance
2、createInstance

renderURL 最终会调用到 WXBridgeContext 的 createInstance 方法:

- (void)createInstance:(NSString *)instance
              template:(NSString *)temp
               options:(NSDictionary *)options
                  data:(id)data
{
    。。。。。。
    NSArray *args = nil;
    if (data){
        args = @[instance, temp, options ?: @{}, data];
    } else {
        args = @[instance, temp, options ?: @{}];
    }

    WX_MONITOR_INSTANCE_PERF_START(WXPTJSCreateInstance, [WXSDKManager instanceForID:instance]);
    [self callJSMethod:@"createInstance" args:args];
    WX_MONITOR_INSTANCE_PERF_END(WXPTJSCreateInstance, [WXSDKManager instanceForID:instance]);
}

传递的 args是一个 array:
instance: instanceID
temp: js 代码
options:包含 bundleUrl 和 debug

options: {
    bundleUrl = "file:///Users/yangshichang/Library/Developer/CoreSimulator/Devices/D5993070-3351-4E74-AEC5-40D97FEC8440/data/Containers/Bundle/Application/5919B561-0EC0-4927-89D8-B2895256D9CF/OperatorWeex.app/bundlejs/index.js";
    debug = 1;
}

js

1、crateInstance

native 调起的 crateInstance 会转发到 runtime/init.js 中的 createInstance

function createInstance (id, code, config, data) {
  let info = instanceMap[id]

  if (!info) {
    // Init instance info.
    info = checkVersion(code) || {}
    if (!frameworks[info.framework]) {
      info.framework = 'Weex'
    }

    // Init instance config.
    config = JSON.parse(JSON.stringify(config || {}))
    config.bundleVersion = info.version
    config.env = JSON.parse(JSON.stringify(global.WXEnvironment || {}))
    console.debug(`[JS Framework] create an ${info.framework}@${config.bundleVersion} instance from ${config.bundleVersion}`)

    const env = {
      info,
      config,
      created: Date.now(),
      framework: info.framework
    }
    env.services = createServices(id, env, runtimeConfig)
    instanceMap[id] = env

    return frameworks[info.framework].createInstance(id, code, config, data, env)
  }
  return new Error(`invalid instance id "${id}"`)
}

这里判断 instance 是否存在,避免重复创建。读取环境信息,判断是哪一个 framework,调用对应 framework 的 createInstance。

生成的 env 对象:

Object = $1

config: {debug: true, bundleUrl: "file:///Users/yangshichang/Library/Developer/CoreS…8-4BB8A4747BC4/OperatorWeex.app/bundlejs/hello.js", bundleVersion: undefined, env: Object}

created: 1500520452139

framework: "Vue"

info: {framework: "Vue"}

services: {service: {}, BroadcastChannel: function}

“Object”原型

因为使用 Vue 写的,所以这里会调用到 weex-vuew-framework.js

function createInstance (
  instanceId,
  appCode,
  config,
  data,
  env
) {
  if ( appCode === void 0 ) appCode = '';
  if ( config === void 0 ) config = {};
  if ( env === void 0 ) env = {};

  // 1. create Document
  var document = new renderer.Document(instanceId, config.bundleUrl);

  // 2. create instance
  var instance = instances[instanceId] = {
    instanceId: instanceId, config: config, data: data,
    document: document
  };

  // 3. create 获取 Module 对象的函数,需要 instance 来获取 instance.document.taskCenter。
  var moduleGetter = genModuleGetter(instanceId);
  // 4. create timerAPIs module
  var timerAPIs = getInstanceTimer(instanceId, moduleGetter);


  // 5. create weex module
  var weexInstanceVar = {
    config: config,
    document: document,
    requireModule: moduleGetter
  };
  Object.freeze(weexInstanceVar);

  // 6. 给 instance 创建 Vue module。
  var Vue = instance.Vue = createVueModuleInstance(instanceId, moduleGetter);

  // 7. create instanceVars,把 上面创建的对象,打包传递给 callFunction, 生成 执行 JSBundle 的匿名函数。
  // The function which create a closure the JS Bundle will run in.
  // It will declare some instance variables like `Vue`, HTML5 Timer APIs etc.
  var instanceVars = Object.assign({
    Vue: Vue,
    weex: weexInstanceVar,
    // deprecated
    __weex_require_module__: weexInstanceVar.requireModule // eslint-disable-line
  }, timerAPIs, env.services);

  // 8. callFunction(instanceVars, appCode),生成 执行 JSBundle 的匿名函数
  if (!callFunctionNative(instanceVars, appCode)) {
    // If failed to compile functionBody on native side,
    // fallback to 'callFunction()'.
    callFunction(instanceVars, appCode);
  }

  // Send `createFinish` signal to native.
  instance.document.taskCenter.send('dom', { action: 'createFinish' }, []);
}

  1. create Document
  2. create instance
  3. create 获取 Module 对象的函数,需要 instance 来获取 instance.document.taskCenter。
  4. create timerAPIs module
  5. create weex 对象,Vue 中写的 weex.requireModue 就是调用这里的 genModuleGetter 的这个方法
  6. 给 instance 创建 Vue module。
  7. create instanceVars,把 上面创建的对象,打包传递给 callFunction, 生成 执行 JSBundle 的匿名函数。
  8. callFunction(instanceVars, appCode),生成 执行 JSBundle 的匿名函数
  9. 发送 instance createFinish 事件。

createInstance(1),创建 Document 对象

Document 在 vdom/document.js

export default function Document (id, url, handler) {
  id = id ? id.toString() : ''
  this.id = id
  this.URL = url

  // 1. 将生成的 doc 添加到 `docMap` 中
  addDoc(id, this)
  // 2. create nodeMap
  this.nodeMap = {}
  // 3. 读取 Listener,Listener 已经废弃掉了,
  const L = Document.Listener || Listener
  // 4. 初始化 Listener,这里 handler 是 undefined。没有值的
  this.listener = new L(id, handler || createHandler(id, Document.handler)) // deprecated
  // 5. create TaskCenter。每一个 Document 都持有一个 TaskCenter。这里 handler 为 undefined,用的是 Document.handler
  this.taskCenter = new TaskCenter(id, handler ? (id, ...args) => handler(...args) : Document.handler)
  // 6. create 一个 document element。也是一个 Element 的对象,把 role 设置为 'documentElement',
  this.createDocumentElement()
}

1、Doucument.handler config.js中 赋值为 sendTasks,调用 global.callNative

2、每一个 Document 都持有一个 TaskCenter,作为 业务代码和 native 交互的通道。TaskCenter 发送的消息 第一个参数都会带上 instanceID。

TaskCenter 的代码在 runtime/task-center.js 。这里 handler 为 nil,所以用的是 Document.handler

taskCenter 的初始化只是设置 instanceId 和 callbackManager,fallback

(1)callbackManager 的作用就是 在 js 调用 native 时,如果参数带有回调函数,则将这个 callback 暂存在 callbackManager 中,将 生成的 callback id 发送给 native,
当 native callback 给 js 时,根据 callback id,取出对应的 callback 执行。

(2)fallback 赋值给 sendTasks

3、documentElement 是作为 根节点 body 的父节点而存在的。
在一个 document 被创建时会自动生成一个 documentElement ,并且 body 应该手动创建并添加到 documentElement 才能工作。bodytype 必须是一个 divlistscroller

documentElement 另外添加了 2 个 函数,appendChildinsertBefore

    Object.defineProperty(el, 'appendChild', {
        configurable: true,
        enumerable: true,
        writable: true,
        value: (node) => {
          appendBody(this, node)
        }
      })

      Object.defineProperty(el, 'insertBefore', {
        configurable: true,
        enumerable: true,
        writable: true,
        value: (node, before) => {
          appendBody(this, node, before)
        }
      })

createInstance(2)创建 instance

var instance = instances[instanceId] = {
  instanceId: instanceId, config: config, data: data,  document: document
};

生成的 instance 示例:

 config: Object

            bundleUrl: "file://…",bundleVersion: undefined,debug: true,

            env: {scale: 3, appVersion: "1.8.3", deviceModel: "x86_64", appName: "OperatorWeex", platform: "iOS", …}

            “Object”原型

    data: undefined

    document: Document

            URL: "file:///…"

            documentElement: Element

                    appendChild: function(node)

                    attr: {}

                    children: [] (0)

                    classStyle: {}

                    depth: 0

                    docId: "2"

                    event: {}

                    insertBefore: function(node, before)

                    nodeId: "139"

                    nodeType: 1

                    ownerDocument: Document {id: "2", URL: "file:///Users/yangshichang/Library/Developer/CoreS…8-4BB8A4747BC4/OperatorWeex.app/bundlejs/hello.js", nodeMap: Object, listener: Listener, taskCenter: TaskCenter, …}

                    pureChildren: [] (0)

                    ref: "_documentElement"

                    role: "documentElement"

                    style: {}

                    type: "document"

                    “Element”原型

            id: "2"

            listener: Listener

                    batched: false

                    handler: function(tasks)

                    id: "2"

                    updates: [] (0)

                    “Listener”原型

            nodeMap: Object

            _documentElement: Element {nodeType: 1, nodeId: "139", ref: "_documentElement", type: "document", attr: {}, …}

                    “Object”原型

            taskCenter: TaskCenter

                    callbackManager: CallbackManager

                            callbacks: [] (0)

                            instanceId: undefined

                            lastCallbackId: 0

                            “CallbackManager”原型

                    instanceId: "2"

                    “TaskCenter”原型

            “Document”原型

    instanceId: "2"

createInstance(3)生成 获取 module 的方法

genModuleGetter: 根据 module name,遍历 native 暴露出来的 methodName,生成 js 对应的 module 。调用对应的方法 都是 转发到 taskCenter 去做转发。

genModuleGetter 会作为 weex.requieModule 传递到 JSBundle 里面,JSBundle 中执行的 weex.requireModule 就是这个函数。

function genModuleGetter (instanceId) {
  var instance = instances[instanceId];
  return function (name) {
    var nativeModule = modules[name] || [];
    var output = {};
    var loop = function ( methodName ) {
      Object.defineProperty(output, methodName, {
        enumerable: true,
        configurable: true,
        get: function proxyGetter () {
          return function () {
            var args = [], len = arguments.length;
            while ( len-- ) args[ len ] = arguments[ len ];

            return instance.document.taskCenter.send('module', { module: name, method: methodName }, args)
          }
        },
        set: function proxySetter (val) {
          if (typeof val === 'function') {
            return instance.document.taskCenter.send('module', { module: name, method: methodName }, [val])
          }
        }
      });
    };

    for (var methodName in nativeModule) loop( methodName );
    return output
  }
}

createInstance(4)创建 timer

超时 等 回调方法。

createInstance(5)创建 Vue

var Vue = instance.Vue = createVueModuleInstance(instanceId, moduleGetter);

创建一个 Vue 函数,作用就是 JSBundle 的解析器。发送指令到 native 进行界面渲染。

function createVueModuleInstance (instanceId, moduleGetter) {

  // 1. create Vue 对象
  var exports = {};
  VueFactory(exports, renderer);
  var Vue = exports.Vue;

  var instance = instances[instanceId];

  // 2. 创建一个函数,判断 element type 是否保留 element
  // patch reserved tag detection to account for dynamically registered
  // components
  var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
  Vue.config.isReservedTag = function (name) {
    return components[name] || isReservedTag(name)
  };

  // 3. 给 Vue 添加 instanceID 和 document 属性
  // expose weex-specific info
  Vue.prototype.$instanceId = instanceId;
  Vue.prototype.$document = instance.document;

  // 4. 给 Vue 添加 requireModule 属性
  // expose weex native module getter on subVue prototype so that
  // vdom runtime modules can access native modules via vnode.context
  Vue.prototype.$requireWeexModule = moduleGetter;

  // 5. 添加一个 beforeCreate 钩子函数,在 root component 创建之前,将 外部 传入的 data 和 $options 中的 data 合并。
  // data 是 createInstance 的时候,从 native 传过来的。
  // 把根 vm 设置为 instance 的 app 属性。
  // Hack `Vue` behavior to handle instance information and data
  // before root component created.
  Vue.mixin({
    beforeCreate: function beforeCreate () {
      var options = this.$options;
      // root component (vm)
      if (options.el) {
        // set external data of instance
        var dataOption = options.data;
        var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};
        options.data = Object.assign(internalData, instance.data);
        // record instance by id
        instance.app = this;
      }
    }
  });

  /**
   * @deprecated Just instance variable `weex.config`
   * Get instance config.
   * @return {object}
   */
  Vue.prototype.$getConfig = function () {
    if (instance.app instanceof Vue) {
      return instance.config
    }
  };

  return Vue
}
  1. create Vue 函数
  2. 创建一个函数,判断 element type 是否保留 element
  3. 给 Vue 添加 instanceID 和 document 属性
  4. 给 Vue 添加 requireModule 属性
  5. 添加一个 beforeCreate 钩子函数,在 root component 创建之前,将 外部 传入的 data 和 $options 中的 data 合并。
    data 是 createInstance 的时候,从 native 传过来的。
VueFactory(exports, renderer);

VueFactory 定义在 weex-vue-framework factory.js。 是打包好的 weex 平台的 vue 核心库。

初始化一个 Vue 函数。

'use strict';

module.exports = function weexFactory (exports, renderer) {

。。。。。。

function initMixin (Vue) {
  Vue.prototype._init = function (options) {
    。。。。。。。
  }
}

。。。。。

function Vue$2 (options) {
  if (process.env.NODE_ENV !== 'production' &&
    !(this instanceof Vue$2)) {
    warn('Vue is a constructor and should be called with the `new` keyword');
  }
  this._init(options);
}

initMixin(Vue$2);
stateMixin(Vue$2);
eventsMixin(Vue$2);
lifecycleMixin(Vue$2);
renderMixin(Vue$2);
。。。。。

/*  */

// install platform specific utils
Vue$2.config.mustUseProp = mustUseProp;
Vue$2.config.isReservedTag = isReservedTag;
Vue$2.config.isUnknownElement = isUnknownElement;

// install platform runtime directives and components
Vue$2.options.directives = platformDirectives;
Vue$2.options.components = platformComponents;

// install platform patch function
Vue$2.prototype.__patch__ = patch;

// wrap mount
Vue$2.prototype.$mount = function (
  el,
  hydrating
) {
  return mountComponent(
    this,
    el && query(el, this.$document),
    hydrating
  )
};

// this entry is built and wrapped with a factory function
// used to generate a fresh copy of Vue for every Weex instance.

exports.Vue = Vue$2;

}
isReservedTag

判断是否是 保留 tag,根据 components 里面的类型 和 Vue.config.isReservedTag

var isReservedTag = makeMap(
  'template,script,style,element,content,slot,link,meta,svg,view,' +
  'a,div,img,image,text,span,richtext,input,switch,textarea,spinner,select,' +
  'slider,slider-neighbor,indicator,trisition,trisition-group,canvas,' +
  'list,cell,header,loading,loading-indicator,refresh,scrollable,scroller,' +
  'video,web,embed,tabbar,tabheader,datepicker,timepicker,marquee,countdown',
  true
);

components 就是 native 注册的 组件。

createInstance callFunction 解析 JSBundle 代码

callFunction 的作用就是解析执行 JSBundle 的代码。

function callFunction (globalObjects, body) {
  var globalKeys = [];
  var globalValues = [];
  for (var key in globalObjects) {
    globalKeys.push(key);
    globalValues.push(globalObjects[key]);
  }
  globalKeys.push(body);

  var result = new (Function.prototype.bind.apply( Function, [ null ].concat( globalKeys) ));
  return result.apply(void 0, globalValues)
}

globalKeys:

Array (10) = $2
0 "Vue"
1 "weex"
2 "__weex_require_module__"
3 "setTimeout"
4 "setInterval"
5 "clearTimeout"
6 "clearInterval"
7 "service"
8 "BroadcastChannel"
9 "// { \"framework\": \"Vue\" }↵/******/ (function(modules) { // webpackBootstrap↵/******/ // The module cache↵/******/ var installedModules …"

“Array”原型

var result = new (Function.prototype.bind.apply( Function, [ null ].concat( globalKeys) ));
生成一个匿名函数,参数为 Vue….BroadcastChannel。函数体为 body

result.apply(void 0, globalValues)
执行 这个匿名函数

function anonymous(Vue, weex, __weex_require_module__, setTimeout, setInterval, clearTimeout, clearInterval, service, BroadcastChannel) {
// { "framework": "Vue" }
        /******/ (function(modules){ // webpackBootstrap
        /******/  // The module cache
        /******/  var installedModules = {};
        /******/  // The require function
        /******/  function __webpack_require__(moduleId){}

        /******/  // expose the modules object (__webpack_modules__)
        /******/  __webpack_require__.m = modules;

        /******/  // expose the module cache
        /******/  __webpack_require__.c = installedModules;

        /******/  // __webpack_public_path__
        /******/  __webpack_require__.p = "";

        /******/  // Load entry module and return exports
        /******/  return __webpack_require__(0);

        })


        ({
        /***/ 0:
        /***/ (function(module, exports, __webpack_require__) {
            .........
            var __vue_exports__, __vue_options__
            var __vue_styles__ = []

            /* styles */
            __vue_styles__.push(__webpack_require__(133)
            )

            /* script */
            __vue_exports__ = __webpack_require__(134)

            /* template */
            var __vue_template__ = __webpack_require__(135)

            .........

            module.exports = __vue_exports__
            module.exports.el = 'true'
            new Vue(module.exports)
        }),

        /***/ 133:
        /***/ (function(module, exports) {}),

        /***/ 134:
        /***/ (function(module, exports) {}),

        /***/ 135:
        /***/ (function(module, exports) {})
        });
}

入口就是 moduleId==0的 module。里面会 把所有的 module 都执行起来,

一般 最后三个就是 Vue 代码中的 templatescriptstyle。具体可在0的函数体中看到

如果 script 中有 require 则 调用 moduleGetter 读取 Module 的方法,并生成 Module。
例如 var event = weex.requireModule('event'); 就会 生成 Event module 对象。

最后一句 new Vue(module.exports) 用解析好的对象作为参数 实例化一个 Vue对象。

new Vue(exports)

从上面的 Vue 函数可以看出 new Vue() 会调用到 Vue._init 方法

function initMixin (Vue) {
  Vue.prototype._init = function (options) {

    // 1. create vm, Vue 的实例化对象。
    var vm = this;

    // 2. 设置 uid
    // a uid
    vm._uid = uid++;

    var startTag, endTag;
    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      startTag = "vue-perf-init:" + (vm._uid);
      endTag = "vue-perf-end:" + (vm._uid);
      mark(startTag);
    }

    // a flag to avoid this being observed
    vm._isVue = true;
    // merge options
    if (options && options._isComponent) {
      // optimize internal component instantiation
      // since dynamic options merging is pretty slow, and none of the
      // internal component options needs special treatment.
      initInternalComponent(vm, options);
    } else {

      // 3. 将传入的这些options选项挂载到vm.$options属性上
      vm.$options = mergeOptions(
        resolveConstructorOptions(vm.constructor),
        options || {},
        vm
      );
    }
    /* istanbul ignore else */
    if (process.env.NODE_ENV !== 'production') {
      initProxy(vm);
    } else {
      vm._renderProxy = vm;
    }
    // expose real self
    vm._self = vm; // 自身的实例

    // 接下来所有的操作都是在这个实例上添加方法

    // lifecycle初始化
    initLifecycle(vm);
    // events初始化 vm._events, 主要是提供vm实例上的$on/$emit/$off/$off等方法
    initEvents(vm);
    // 初始化渲染函数,在vm上绑定$createElement方法
    initRender(vm);
    // 执行钩子函数, beforeCreate
    callHook(vm, 'beforeCreate');
    initInjections(vm); // resolve injections before data/props
    // Observe data添加对data的监听, 将data中的 key 转化为getters/setters
    initState(vm);
    initProvide(vm); // resolve provide after data/props
    // 执行钩子函数, created
    callHook(vm, 'created');

    /* istanbul ignore if */
    if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
      vm._name = formatComponentName(vm, false);
      mark(endTag);
      measure(((vm._name) + " init"), startTag, endTag);
    }

    // vm挂载的根元素, el 在 JSBundle 中设置为 true
    if (vm.$options.el) {
      vm.$mount(vm.$options.el);
    }
  };
}

options 就是 解析好的 JSBundle 的对象。

Vue.init(options) (1) mergeOptions

merge options 的作用就是 把 连个 对象合成一个。这里 就是 把 Vue 的方法 合并到 vm.$options 上。

function mergeOptions (
  parent,
  child,
  vm
) {
  。。。。。。
  var options = {};
  var key;
  for (key in parent) {
    mergeField(key);
  }
  for (key in child) {
    if (!hasOwn(parent, key)) {
      mergeField(key);
    }
  }
  function mergeField (key) {
    var strat = strats[key] || defaultStrat;
    options[key] = strat(parent[key], child[key], vm, key);
  }
  return options
}

这里的 parent 就是 Vue 的构造函数,是:

parent:

Object = $5

_base: function(options)

beforeCreate: [function] (1)

components: {Transition: Object, TransitionGroup: Object}

directives: {}

filters: {}

“Object”原型

Vue.init(options)(2)initProxy(vm)

代理 vm 的 get 方法,拦截 vm 属性的 读取操作。如果 vm 的某一个属性不存在,则抛出一个warning。

Vue.init(options)(3)initLifecycle(vm)

初始化 vm 生命周期的关键属性值。

  vm.$parent = parent;
  vm.$root = parent ? parent.$root : vm;

  vm.$children = [];
  vm.$refs = {};

  vm._watcher = null;
  vm._inactive = null;
  vm._directInactive = false;
  vm._isMounted = false;
  vm._isDestroyed = false;
  vm._isBeingDestroyed = false;

Vue.init(options)(4)initEvents(vm)

function initEvents (vm) {
  vm._events = Object.create(null);
  vm._hasHookEvent = false;
  // init parent attached events
  var listeners = vm.$options._parentListeners;
  if (listeners) {
    updateComponentListeners(vm, listeners);
  }
}

初始化 节点上绑定的 on 事件。这里先初始化一个空的 event对象,判断如果 判断 vm 是否有 _parentListeners,有才会更新。

其实 每一个独立文件的 component 都会创建一个 vm。这里初始化,就是指更新 该 vm 作为 子节点时候,是否绑定有事件。

Vue.init(options)(5)initRender(vm)

function initRender (vm) {
  ......
  // bind the createElement fn to this instance
  // so that we get proper render context inside it.
  // args order: tag, data, children, normalizationType, alwaysNormalize
  // internal version is used by render functions compiled from templates
  vm._c = function (a, b, c, d) { return createElement(vm, a, b, c, d, false); };
  // normalization is always applied for the public version, used in
  // user-written render functions.
  vm.$createElement = function (a, b, c, d) { return createElement(vm, a, b, c, d, true); };
}

绑定 createElement 方法到 vm,渲染 js 都是调用这里的 createElement。
这两个绑定 最后一个参数不同,alwaysNormalize

Vue.init(options)(6)callHook(vm, 'beforeCreate')

beforeCreatecreateVueModuleInstance 方法中进行了设置,主要是为了 把 vm 中的 data 和 native 传过来的 data 合并。

beforeCreate:

var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};

如果 dataOption 是 函数,则只需,否则直接读取。

Vue.init(options)(3)initInjections(vm)

Vue.init(options)(3)initProvide(vm)

provideinject 主要为高阶插件/组件库提供用例。并不推荐直接用于应用程序代码中。

这对选项需要一起使用,以允许一个祖先组件向其所有子孙后代注入一个依赖,不论组件层次有多深,并在起上下游关系成立的时间里始终生效。如果你熟悉 React,这与 React 的上下文特性很相似。

var Provider = {
  provide: {
    foo: 'bar'
  },
  // ...
}
var Child = {
  inject: ['foo'],
  created () {
    console.log(this.foo) // -> "bar"
  }
  // ...
}

Vue.init(options)(3)initState(vm)

这里面初始化 vm 的data,method 等等,非常重要

function initState (vm) {
  // 1. 在vm上初始化一个_watchers数组,缓存这个vm上的所有watcher
  vm._watchers = [];
  // 2. 读取 vm 的 options。
  var opts = vm.$options;

  // 下面这些都对应 
                    
                    

你可能感兴趣的:(加载 JSBundle)