AngularJS-源码阅读(六)

然后,我们看看AngularJS关于provider、constant等实现。

var providerSuffix="Provider";//这个参数,在providerCache写属性名时使用,用以区分constant以及普通的provider注入
  function provider(name, provider_) {
    assertNotHasOwnProperty(name, 'service');//保证name !== 'hasOwnProperty'
    if (isFunction(provider_) || isArray(provider_)) {
      provider_ = providerInjector.instantiate(provider_);//将传入的provider进行注入。providerInjector                                                          //以后讲解
    }
    if (!provider_.$get) {//每一个provider 都必须有$get属性。。
      throw $injectorMinErr('pget', "Provider '{0}' must define $get factory method.", name);
    }
    return providerCache[name + providerSuffix] = provider_;
  }

  function factory(name, factoryFn) { return provider(name, { $get: factoryFn }); }

  function service(name, constructor) {
    return factory(name, ['$injector', function($injector) {
      return $injector.instantiate(constructor);
    }]);
  }

  function valueFn(value) {return function() {return value;};}
  function value(name, val) { return factory(name, valueFn(val)); }

  function constant(name, value) {
    assertNotHasOwnProperty(name, 'constant');//name must not eqauls "hasOwnProperty"
    providerCache[name] = value;
    instanceCache[name] = value;
    //这样做之后,可以$provider,$service 中都访问
  }

  下面为createInternalInjector,ProviderInjector由createInternalInjector实现。

  var INSTANTIATING = {};//避免循环引用自己
  var path=[];//由来做错误提示的。
  function createInternalInjector(cache, factory) {

    function getService(serviceName) {
      if (cache.hasOwnProperty(serviceName)) {
        if (cache[serviceName] === INSTANTIATING) {
          throw $injectorMinErr('cdep', 'Circular dependency found: {0}', path.join(' <- '));
        }
        return cache[serviceName];
      } else {
        try {//当根据服务名称搜索不到时,
            //先让cache[serviceName]=INSTANTIATING,factory函数会返回值或抛异常
            //而factory在返回值时,可能还会在调用同一个module下的createInternalInjector里的getService方法
            //这时,path的记录就可用来写注入异常路径提示,而INSTANTIATING则可以进行检验是否是循环引用了
          path.unshift(serviceName);
          cache[serviceName] = INSTANTIATING;
          return cache[serviceName] = factory(serviceName);
        } finally {
          path.shift();//用来清空路径信息
        }
      }
    }

    function invoke(fn, self, locals){
      var args = [],
          $inject = annotate(fn),//获取需要注入的引用名称数组
          length, i,
          key;

      for(i = 0, length = $inject.length; i < length; i++) {
        key = $inject[i];
        if (typeof key !== 'string') {
          throw $injectorMinErr('itkn',
                  'Incorrect injection token! Expected service name as string, got {0}', key);
        }
        args.push(
          locals && locals.hasOwnProperty(key)//如果当前module没有,则取找cache缓存(注入的其它module)中
          ? locals[key]
          : getService(key)
        );
      }
      if (!fn.$inject) {        
        // this means that we must be an array.
        //fn经过annotate处理后,如果没有$inject属性,则证明,fn为['a','b',function(a,b){}] 的形式。
        fn = fn[length];
      }

      // http://jsperf.com/angularjs-invoke-apply-vs-switch
      // #5388
      return fn.apply(self, args);
    }

    function instantiate(Type, locals) {//将传入的Type的原型注入到新实例化的函数或者object原型上去。
    
      var Constructor = function() {},
          instance, returnedValue;

      // Check if Type is annotated and use just the given function at n-1 as parameter
      // e.g. someModule.factory('greeter', ['$window', function(renamed$window) {}]);
      Constructor.prototype = (isArray(Type) ? Type[Type.length - 1] : Type).prototype;
      instance = new Constructor();//生成一个全新的函数实例用以加载需要注入的function
      returnedValue = invoke(Type, instance, locals);

      return isObject(returnedValue) || isFunction(returnedValue) ? returnedValue : instance;
    }

    return {
      invoke: invoke,
      instantiate: instantiate,
      get: getService,
      annotate: annotate,//暴露出annotate 函数。
      has: function(name) {
        
        return providerCache.hasOwnProperty(name + providerSuffix) || cache.hasOwnProperty(name);
      }
    };
  }
}

简洁点记忆就是:

createInternalInjector返回一个object。

createInternalInjector(cache,factory){
return
    {
        /*
        *fn.apply(self,args) args来源于locals[key]
        *和get[key],key值为fn的注入参数。
        */
        invoke:  function(fn, self, locals){...}
        
        /*
        *先根据cache,cache[serviceName],如果undefined,
        *则factory(serviceName)获取
        */
        get:function(serviceName){...}
        
        /*
        *生成一个不带参数的instance=function(){},并且intance获得Type的prototype,
        *调用returnvalue=invoke(Type, instance, locals),如果returnvalue不是object或者
        *function,返回instance,否则返回returnvalue
        */
        instantiate:function(Type, locals){...}   
        
        annotate:function(fn){//获取要注入的参数名称}     

        has:function(name){//检测providerCach和cache有没有name atrribute}
    }
}






你可能感兴趣的:(AngularJS-源码阅读(六))