Angular 源码解析系列 - 掘金

来源: Angular 源码解析系列 – 掘金

加载应用依赖模块以及内置的ng模块等,就像之前说的类似这样:['ng', [$provide, function($provide){...}], 'xx']
执行每个模块的_runBlocks,可以理解injector创建完后模块的初始化(通过myModule.run(...)注册的)

  function loadModules(modulesToLoad){
    var runBlocks = [], moduleFn;

    // 循环加载每个module,
    // 1. 注册每个模块上挂载的service(也就是_invokeQueue)
    // 2. 执行每个模块的自身的回调(也就是_configBlocks)
    // 3. 通过递归搜集所有(依赖)模块的_runBlocks,并返回
    forEach(modulesToLoad, function(module) {

      // 判断模块是否已经加载过
      if (loadedModules.get(module)) return;

      // 设置模块已经加载过
      loadedModules.put(module, true);

      function runInvokeQueue(queue) {
        var i, ii;
        for(i = 0, ii = queue.length; i < ii; i++) {

          var invokeArgs = queue[i],
              provider = providerInjector.get(invokeArgs[0]);

          // 通过providerInjector获取指定服务(类),传递参数并执行指定方法
          provider[invokeArgs[1]].apply(provider, invokeArgs[2]);
        }
      }

      // 模块可以是以下三种情况:
      // 1. 字符串表示模块名(注册过的模块),如:'ng'模块
      // 2. 普通函数(也可以是隐式声明依赖的函数),如:function($provider) {...}
      // 3. 数组(即声明依赖的函数)如:[$provide, function($provide){...}
      try {
        if (isString(module)) {
          // 获取通过模块名获取模块对象
          moduleFn = angularModule(module);
          // 通过递归加载所有依赖模块,并且获取所有依赖模块(包括自身)的_runBlocks
          runBlocks = runBlocks.concat(loadModules(moduleFn.requires)).concat(moduleFn._runBlocks);
          // 遍历_invokeQueue数组依次执行$provider服务的指定方法(如:factory,value等)
          runInvokeQueue(moduleFn._invokeQueue);
          // 遍历_configBlocks数组依次执行$injector服务的invoke方法(即依赖注入并执行回调)
          runInvokeQueue(moduleFn._configBlocks);

        // 如果module是函数或者数组(可认为是匿名模块),那么依赖注入后直接执行
        // 并将返回值保存到runBlocks(可能是函数,又将继续执行)
        } else if (isFunction(module)) {
            runBlocks.push(providerInjector.invoke(module));
        } else if (isArray(module)) {
            runBlocks.push(providerInjector.invoke(module));
        } else {
          assertArgFn(module, 'module');
        }
      } catch (e) {
        if (isArray(module)) {
          module = module[module.length - 1];
        }
        if (e.message && e.stack && e.stack.indexOf(e.message) == -1) {
          e = e.message + '\n' + e.stack;
        }
        throw $injectorMinErr('modulerr', "Failed to instantiate module {0} due to:\n{1}",
                  module, e.stack || e.message || e);
      }
    });
    return runBlocks;
  }
复制代码

到这里在注册ng模块时的回调,在runInvokeQueue(moduleFn._configBlocks);已经执行过了,也就意味着许许多多的内置模块已经存入providerCache中了,所以在后面的依赖注入中我们可以随意调用。

最后

如果不对的地方,欢迎留言指正,新浪微博 – Lovesueee

作者:小鱼二
链接:https://juejin.im/post/6844903440217276423
来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

赞(0) 打赏
分享到: 更多 (0)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏