源碼裏是這麼描述的:
Factory that constructs {@link $cacheFactory.Cache Cache} objects and gives access to
them.
意思就是經過cacheFactory能夠構造一個Cache對象來給予訪問和執行權限。javascript
這個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內部使用。html
<!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>
看了上面這個一個簡單的例子,讀者可能會產生以下疑惑:java
咱們首先來看第一個問題,這個問題要牽涉到angular裏面的依賴注入機制,咱們前面的分析也講過,
angular會在啓動以前經過調用publishExternalAPI
函數先發布一些擴展API,同時定義ng
模塊,在定義ng模塊的時候就傳入了注入provider的方法angularjs
angularModule('ng', ['ngLocale'], ['$provide', //經過參數注入$provide function ngModule($provide) { ///部分代碼省略 $provide.provider({ $cacheFactory: $CacheFactoryProvider, }); }])
$cacheFactory出現了,它是經過javascript的鍵值對象做爲鍵傳給provider方法。那麼它是如何存儲
對象的呢?首先咱們看它的定義:算法
內部定義了依賴注入核心的$get
方法,$get
方法返回cacheFactory方法(也就是上面實例代碼裏的
$cacheFactory
參數)。api
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; } }
存儲分爲這幾個核心方法:put
,refresh
,remove
,link
緩存
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; }
Retrieves named data stored in the {@link $cacheFactory.Cache Cache} object
獲取存儲在cache對象中的指定數據app
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]; }
Removes an entry from the {@link $cacheFactory.Cache Cache} object.
從cache對象刪除一個entryide
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--; }
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 } }
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 } }
歡迎關注個人公衆號,獲取最新源碼解析文章!