angular源码剖析之Provider系列--CacheFactoryProvider
CacheFactoryProvider 简介
源码里是这么描述的:
Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
them.
意思就是通过cacheFactory可以构造一个Cache对象来给予访问和执行权限。
这个Cache对象官方文档是这么说的:
A cache object used to store and retrieve data, primarily used by $http and the script directive to cache templates and other data.
用我自己的话来说就是 提供存储和访问缓存对象的服务,angular内部主要被$http,script指令用于
缓存template和其他数据。我们自己可以在Controller内部使用。
CacheFactoryProvider 用法
<!doctype html>
<html lang="en" ng-app="myapp">
<head>
<meta charset="UTF-8">
<meta name="Generator" content="EditPlus®">
<meta name="Author" content="">
<meta name="Keywords" content="">
<meta name="Description" content="">
<title>Document</title>
<script src="js/angular.js"></script>
</head>
<body>
<div ng-controller="MyController">
</div>
<script >
var app=angular.module('myapp',[]);
app.controller('MyController',function($scope,$cacheFactory){
var myCache = $cacheFactory("myCache",{capacity: 6});
//var myCache1 = $cacheFactory("myCache",{capacity: 6}); //会报错
myCache.put("name","john");
myCache.put("name1","wonder");
myCache.put("name","john");
});
app.controller('getCacheController',['$scope','$cacheFactory',
function($scope,$cacheFactory){
var cache = $cacheFactory.get('myCache');
var name = cache.get('name');
console.log(name); //打印john
}]);
</script>
</body>
</html>
看了上面这个一个简单的例子,读者可能会产生如下疑惑:
- 不是名为CacheFactoryProvider吗,怎么在代码里只看到cacheFactory呢?
- cacheFactory是怎么存储对象的?
下面我们来依次解答这两个问题
$cacheFactory的注入
我们首先来看第一个问题,这个问题要牵涉到angular里面的依赖注入机制,我们前面的分析也讲过,
angular会在启动之前通过调用publishExternalAPI 函数先发布一些扩展API,同时定义ng
模块,在定义ng模块的时候就传入了注入provider的方法
angularModule('ng', ['ngLocale'], ['$provide',
//通过参数注入$provide
function ngModule($provide) {
///部分代码省略
$provide.provider({
$cacheFactory: $CacheFactoryProvider,
});
}])
$cacheFactory出现了,它是通过javascript的键值对象作为键传给provider方法。那么它是如何存储
对象的呢?首先我们看它的定义:
CacheFactoryProvider的定义
内部定义了依赖注入核心的$get方法,$get方法返回cacheFactory方法(也就是上面实例代码里的
$cacheFactory参数)。
function $CacheFactoryProvider() {
//定义$get方法供依赖调用
//controller中获取cacheFactory时会调用此方法
//这个$get方法也是获取provider的关键方法
this.$get = function() {
var caches = {};//闭包的一个运用
function cacheFactory(cacheId, options) {
//部分代码省略
//可以用if来判断
if (cacheId in caches) {//如果caches中已经存在cacheId
//实例代码里抛出的错误就在此处、
//统一调用minErr函数
throw minErr('$cacheFactory')('iid', "CacheId '{0}' is already taken!"
, cacheId);
}
var size = 0,
//把options 和{id:cacheId} 放入{} 中 不是深拷贝
stats = extend({}, options, {id: cacheId}),
data = createMap(),//通过Object.create(null) 创建个空对象
capacity = (options && options.capacity) || Number.MAX_VALUE,
lruHash = createMap(),
freshEnd = null,
staleEnd = null;
//返回caches中的一个对象
return caches[cacheId] = {
//省略部分代码
//存储里讲解
put:function(key,value){
},
get: function(key) {
},
remove: function(key) {
},
removeAll: function() {
},
destroy: function() {
},
info: function() {
}
}
//刷新节点次序
function refresh(entry) {
}
//
function link(nextEntry, prevEntry) {
}
}
//所有的缓存
cacheFactory.info = function() {
var info = {};
forEach(caches, function(cache, cacheId) {
info[cacheId] = cache.info();
});
return info;
};
cacheFactory.get = function(cacheId) {
return caches[cacheId];
};
return cacheFactory;
}
}
CacheFactoryProvider的存储
存储分为这几个核心方法:put,refresh,remove,link
put函数
value会放入data对象中,key会放入lruHash链表
put: function(key, value) {
if (isUndefined(value)) return;
//如果设定的capcity小于maxvalue
if (capacity < Number.MAX_VALUE) {
//lruHash 存了当前的key 还有可能是 p 和n (previous和next)
var lruEntry = lruHash[key] || (lruHash[key] = {key: key});
//刷新各节点的次序
refresh(lruEntry);//把当前entry放入链表末尾
}
//如果key 在data里不存在 那么增加size
if (!(key in data)) size++;
data[key] = value;
//当大于capacity时 会清除最早加入的那个
if (size > capacity) {
this.remove(staleEnd.key);//移除淘汰节点stableEnd
}
return value;
}
get函数
Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object
获取存储在cache对象中的指定数据
get: function(key) {
if (capacity < Number.MAX_VALUE) {
var lruEntry = lruHash[key];
if (!lruEntry) return;
// 获取first的时候 因为staleEnd为first 所以会让staleEnd指向 second
// 内部会执行link 使得 second.p = null
// first.p = third third.n = first
//stableEnd为 second freshEnd为first
refresh(lruEntry);
}
return data[key];
}
remove函数
Removes an entry from the {@link $cacheFactory.Cache Cache} object.
从cache对象删除一个entry
remove: function(key) {
//如果capacity小于maxvalue
if (capacity < Number.MAX_VALUE) {
//先取出当前key的entry
var lruEntry = lruHash[key];
if (!lruEntry) return;
//第一次超过时 freshEnd 为third lryEntry为first
if (lruEntry == freshEnd) freshEnd = lruEntry.p;
//第一次超过时 staleEnd 为first lryEntry为first
//所以 会让 stalEnd 指向second 以便于下次移除时
if (lruEntry == staleEnd) staleEnd = lruEntry.n;
//把淘汰节点的一个节点选中
//第一次超过时 lryEntry.n为 second lryEntry.p 为null
//执行结果为 second.p = null
link(lruEntry.n,lruEntry.p);
//把当前key从lruHash中删除
delete lruHash[key];
}
if (!(key in data)) return;
delete data[key];
size--;
}
refresh函数
makes the entry the freshEnd of the LRU linked list。
把entry 放入链表的末尾
function refresh(entry) {
if (entry != freshEnd) {
if (!staleEnd) { //staleEnd为空那么就让他指向当前entry
staleEnd = entry;
} else if (staleEnd == entry) {
//如果淘汰节点等于当前节点
staleEnd = entry.n; //用于把 当前的下一个节点 用作淘汰节点
}
//放入第一个元素时 entry.n,entry.p都为undefined
link(entry.n, entry.p); //当前的上一个节点 和当前的下一个节点
link(entry, freshEnd); // 当前的节点 和 最新的末尾节点
freshEnd = entry;
freshEnd.n = null;
//第一次执行完 结果为: freshEnd = first staleEnd为first
//first.p=null first.n=null
//第二次执行完 结果为:freshEnd = second staleEnd为first
// first.p=null first.n= second
// scecond.p = first scecond.n = null
//第三次执行完 freshEnd = third staleEnd为first first.p=null
//first.n= second
// second.p = first second.n = null
// third.p = second third.n = null
}
}
link函数
bidirectionally(双向链表) links two entries of the LRU linked list
双向链接链表里的两个元素。
function link(nextEntry, prevEntry) {
//undefined 不等于undefined
if (nextEntry != prevEntry) {
//
if (nextEntry) nextEntry.p = prevEntry;
//p stands for previous, 'prev' didn't minify
if (prevEntry) prevEntry.n = nextEntry;
//n stands for next, 'next' didn't minify
}
}

欢迎关注我的公众号,获取最新源码解析文章!
参考资料:
angular源码剖析之Provider系列--CacheFactoryProvider的更多相关文章
- angular源码剖析之Provider系列--QProvider
QProvider 简介 源码里是这么描述的: A service that helps you run functions asynchronously, and use their return ...
- angular源码阅读,依赖注入的原理:injector,provider,module之间的关系。
最开始使用angular的时候,总是觉得它的依赖注入方式非常神奇. 如果你跳槽的时候对新公司说,我曾经使用过angular,那他们肯定会问你angular的依赖注入原理是什么? 这篇博客其实是angu ...
- 【安卓网络请求开源框架Volley源码解析系列】定制自己的Request请求及Volley框架源码剖析
通过前面的学习我们已经掌握了Volley的基本用法,没看过的建议大家先去阅读我的博文[安卓网络请求开源框架Volley源码解析系列]初识Volley及其基本用法.如StringRequest用来请求一 ...
- 【java集合框架源码剖析系列】java源码剖析之TreeSet
本博客将从源码的角度带领大家学习TreeSet相关的知识. 一TreeSet类的定义: public class TreeSet<E> extends AbstractSet<E&g ...
- 【java集合框架源码剖析系列】java源码剖析之HashSet
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于HashSet的知识. 一HashSet的定义: public class HashSet&l ...
- 【java集合框架源码剖析系列】java源码剖析之TreeMap
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本.本博客将从源码角度带领大家学习关于TreeMap的知识. 一TreeMap的定义: public class TreeMap&l ...
- 【java集合框架源码剖析系列】java源码剖析之ArrayList
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 本博客将从源码角度带领大家学习关于ArrayList的知识. 一ArrayList类的定义: public class Arr ...
- 【java集合框架源码剖析系列】java源码剖析之LinkedList
注:博主java集合框架源码剖析系列的源码全部基于JDK1.8.0版本. 在实际项目中LinkedList也是使用频率非常高的一种集合,本博客将从源码角度带领大家学习关于LinkedList的知识. ...
- 【java集合框架源码剖析系列】java源码剖析之HashMap
前言:之所以打算写java集合框架源码剖析系列博客是因为自己反思了一下阿里内推一面的失败(估计没过,因为写此博客已距阿里巴巴一面一个星期),当时面试完之后感觉自己回答的挺好的,而且据面试官最后说的这几 ...
随机推荐
- 【Todo】UDP P2P打洞原理
参考以下两篇文章: https://my.oschina.net/ososchina/blog/369206 http://m.blog.csdn.net/article/details?id=666 ...
- keras函数式编程(多任务学习,共享网络层)
https://keras.io/zh/ https://keras.io/zh/getting-started/functional-api-guide/ https://github.com/ke ...
- [Unit Testing] Test async function with Jasmine
Most of time, when we want to test function call inside a promise, we can do: it('Should be async', ...
- 出现二个奇葩bug
1.js中少了个单引號,指定的href嵌套指定的地址.单双引號混合加入的情况下一点都不好找.让人头痛的是在chrome,ie11下没有出现js报错,在IE8下报html页面第一行出错.少了个;号 2. ...
- AAuto如何发布EXE文件
1 如下图所示,谷歌翻译是AAuto提供的源码,我们现在把它做成软件.点击编译,注意看底部状态栏提示,编译之后的谷歌翻译还是aau格式的,双击可以直接运行.但是体积变大了,而且已经是二进制文件,无法再 ...
- Dubbo简单介绍及实例
1.概念 Dubbo是一个分布式服务框架,以及阿里巴巴内部的SOA服务化治理方案的核心框架.其功能主要包含:高性能NIO通讯及多协议集成.服务动态寻址与路由.软负载均衡与容错,依赖分析与降级等. 说通 ...
- weexpack build android 和 weexpack run android 报错 及 解决方案
1. weexpack build android (1)Configuring > 0/3 projects > root project > Resolving dependen ...
- Yii自动生成项目
我喜欢尝试新鲜的东西.以前一直用gii生成工具,前几天突然发现用shell的方法,感觉很不错.特此总结一下yii的几个命令. gii的工具页面: - Controller Generator ...
- Objective C运行时(runtime)技术总结,好强大的runtime
前言: Objective C的runtime技术功能非常强大,能够在运行时获取并修改类的各种信息,包括获取方法列表.属性列表.变量列表,修改方法.属性,增加方法,属性等等,本文对相 ...
- 设计模式学习笔记——Template Method模板方法模式
可能是最简单的设计模式. 而且你我都用过而不自知. 因为,模板方法模式也者,就是面向对象中的继承.公用部分放在父类,子类继承父类,然后扩展.呵呵.