啃食Angular之Provider

为加深我们对angular的进一步理解,给大家准备了一些骨头,希望各位分头去啃,然后与大家分享。

单例模式

服务具有唯一的名字,所以无论这个服务被注入到任何地方,对象始终只有一个实例。(银角大王举起葫芦说:我叫你一声,你敢答应吗)啥意思?

依赖注入

你不必关心怎么创建一个实例,只需要声明自己需要哪个服务,就会自动送到你碗里来。(咦,这不是哆啦A梦的百宝袋么?)啥意思?

方式灵活

按照每个程序猿的编程习惯,你可以选择方式的菜谱来自定义服务。(Angular给你准备的5道菜:Value, Factory, Service, Provider and Constant)啥意思?


往期剧情回顾

本期英雄介绍

版本代号:1.3.7

版本名称:leaky-obstruction

发布时间:2014.12.16

源码大小: 25811行 108568字 压缩后122KB

function $AnchorScrollProvider() {

  var autoScrollingEnabled = true;

  this.disableAutoScrolling = function() {
    autoScrollingEnabled = false;
  };

  this.$get = ['$window', '$location', '$rootScope', function($window, $location, $rootScope) {
    var document = $window.document;

    function getFirstAnchor(list) {
      var result = null;
      Array.prototype.some.call(list, function(element) {
        if (nodeName_(element) === 'a') {
          result = element;
          return true;
        }
      });
      return result;
    }

    function getYOffset() {

      var offset = scroll.yOffset;

      if (isFunction(offset)) {
        offset = offset();
      } else if (isElement(offset)) {
        var elem = offset[0];
        var style = $window.getComputedStyle(elem);
        if (style.position !== 'fixed') {
          offset = 0;
        } else {
          offset = elem.getBoundingClientRect().bottom;
        }
      } else if (!isNumber(offset)) {
        offset = 0;
      }

      return offset;
    }

    function scrollTo(elem) {
      if (elem) {
        elem.scrollIntoView();

        var offset = getYOffset();

        if (offset) {

          var elemTop = elem.getBoundingClientRect().top;
          $window.scrollBy(0, elemTop - offset);
        }
      } else {
        $window.scrollTo(0, 0);
      }
    }

    function scroll() {
      var hash = $location.hash(), elm;

      // empty hash, scroll to the top of the page
      if (!hash) scrollTo(null);

      // element with given id
      else if ((elm = document.getElementById(hash))) scrollTo(elm);

      // first anchor with given name :-D
      else if ((elm = getFirstAnchor(document.getElementsByName(hash)))) scrollTo(elm);

      // no element and hash == 'top', scroll to the top of the page
      else if (hash === 'top') scrollTo(null);
    }

    if (autoScrollingEnabled) {
      $rootScope.$watch(function autoScrollWatch() {return $location.hash();},
        function autoScrollWatchAction(newVal, oldVal) {
          // skip the initial scroll if $location.hash is empty
          if (newVal === oldVal && newVal === '') return;

          jqLiteDocumentLoaded(function() {
            $rootScope.$evalAsync(scroll);
          });
        });
    }

    return scroll;
  }];
}
                    

                        //提取几段代码来分析
function $CompileProvider($provide, $$sanitizeUriProvider) {
  var hasDirectives = {},
      Suffix = 'Directive',
      COMMENT_DIRECTIVE_REGEXP = /^\s*directive\:\s*([\w\-]+)\s+(.*)$/,
      CLASS_DIRECTIVE_REGEXP = /(([\w\-]+)(?:\:([^;]+))?;?)/,
      ALL_OR_NOTHING_ATTRS = makeMap('ngSrc,ngSrcset,src,srcset'),
      REQUIRE_PREFIX_REGEXP = /^(?:(\^\^?)?(\?)?(\^\^?)?)?/;
      var EVENT_HANDLER_ATTR_REGEXP = /^(on[a-z]+|formaction)$/;

      function parseIsolateBindings(scope, directiveName) {};

      this.directive = function registerDirective(name, directiveFactory){};

      this.aHrefSanitizationWhitelist = function(regexp){};

      this.imgSrcSanitizationWhitelist = function(regexp){};

       var debugInfoEnabled = true;
       this.debugInfoEnabled = function(enabled){};

       this.$get = [
            '$injector', '$interpolate', '$exceptionHandler', '$templateRequest', '$parse',
            '$controller', '$rootScope', '$document', '$sce', '$animate', '$$sanitizeUri',
             function($injector,   $interpolate,   $exceptionHandler,   $templateRequest,   $parse,
             $controller,   $rootScope,   $document,   $sce,   $animate,   $$sanitizeUri) {};
                     
而写成代码,就成为这个鬼样了:
$FilterProvider.$inject = ['$provide'];
function $FilterProvider($provide) {
  var suffix = 'Filter';
  function register(name, factory) {
    if (isObject(name)) {
      var filters = {};
      forEach(name, function(filter, key) {
        filters[key] = register(key, filter);
      });
      return filters;
    } else {
      return $provide.factory(name + suffix, factory);
    }
  }
  this.register = register;

  this.$get = ['$injector', function($injector) {
    return function(name) {
      return $injector.get(name + suffix);
    };
  }];
                          register('currency', currencyFilter);
  register('date', dateFilter);
  register('filter', filterFilter);
  register('json', jsonFilter);
  register('limitTo', limitToFilter);
  register('lowercase', lowercaseFilter);
  register('number', numberFilter);
  register('orderBy', orderByFilter);
  register('uppercase', uppercaseFilter);
}
                     
互联网时代,我们必须了解一些数据请求:
var defaults = this.defaults = {
    // transform incoming response data
    transformResponse: [defaultHttpResponseTransform],

    // transform outgoing request data
    transformRequest: [function(d) {
      return isObject(d) && !isFile(d) && !isBlob(d) && !isFormData(d) ? toJson(d) : d;
    }],

    // default headers
    headers: {
      common: {
        'Accept': 'application/json, text/plain, */*'
      },
      post:   shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
      put:    shallowCopy(CONTENT_TYPE_APPLICATION_JSON),
      patch:  shallowCopy(CONTENT_TYPE_APPLICATION_JSON)
    },

    xsrfCookieName: 'XSRF-TOKEN',
    xsrfHeaderName: 'X-XSRF-TOKEN'
  };

this.$get = ['$httpBackend', '$browser', '$cacheFactory', '$rootScope', '$q', '$injector',
function($httpBackend, $browser, $cacheFactory, $rootScope, $q, $injector) {};

function $http(requestConfig){};
                     
function $LogProvider() {
  var debug = true,
      self = this;

this.$get = ['$window', function($window) {
    return {
      log: consoleLog('log'),
      info: consoleLog('info'),
      warn: consoleLog('warn'),
      error: consoleLog('error'),
      debug: (function() {
        var fn = conso
        return function() {
          if (debug) {
            fn.apply(self, arguments);
          }
        };
      }())
    };

function formatError(arg) {
      if (arg instanceof Error) {
        if (arg.stack) {
          arg = (arg.message && arg.stack.indexOf(arg.message) === -1)
              ? 'Error: ' + arg.message + '\n' + arg.stack
              : arg.stack;
        } else if (arg.sourceURL) {
          arg = arg.message + '\n' + arg.sourceURL + ':' + arg.line;
        }
      }
      return arg;
    }

    function consoleLog(type) {
      var console = $window.console || {},
          logFn = console[type] || console.log || noop,
          hasApply = false;

      try {
        hasApply = !!logFn.apply;
      } catch (e) {}

      if (hasApply) {
        return function() {
          var args = [];
          forEach(arguments, function(arg) {
            args.push(formatError(arg));
          });
          return logFn.apply(console, args);
        };
      }


      return function(arg1, arg2) {
        logFn(arg1, arg2 == null ? '' : arg2);
      };
    }
                    
                        //初始化变量
                        var TTL = 10;
                        var $rootScopeMinErr = minErr('$rootScope');
                        var lastDirtyWatch = null;
                        var applyAsyncId = null;

                        //构造子函数
                        this.$get = ['$injector', '$exceptionHandler', '$parse', '$browser',
                        function($injector, $exceptionHandler, $parse, $browser) {

                        //很重要的一个模型
                        function Scope() {
                        this.$id = nextUid();
                        this.$$phase = this.$parent = this.$$watchers =
                        this.$$nextSibling = this.$$prevSibling =
                        this.$$childHead = this.$$childTail = null;
                        this.$root = this;
                        this.$$destroyed = false;
                        this.$$listeners = {};
                        this.$$listenerCount = {};
                        this.$$isolateBindings = null;
                        }

                        Scope.prototype = {
                        constructor: Scope,

                        $new: function(isolate, parent){},
                        $watch: function(watchExp, listener, objectEquality){},
                        $digest: function(){},
                        $destroy: function(){},
                        $eval: function(expr, locals){},
                        $apply: function(expr){},
                        $on: function(name, listener){},
                        $emit: function(name, args){},
                        $broadcast: function(name, args){}
                        //还有好多好多常用东西,原来都定义在这里了呀!
                        }

                        }

                    

曲终人散

终于啃完了, 是不是要随手转发正能量?