Dashboard sipadu mbip
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

cache-base.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434
  1. /*
  2. Copyright (c) 2010, Yahoo! Inc. All rights reserved.
  3. Code licensed under the BSD License:
  4. http://developer.yahoo.com/yui/license.html
  5. version: 3.4.0
  6. build: nightly
  7. */
  8. YUI.add('cache-base', function(Y) {
  9. /**
  10. * The Cache utility provides a common configurable interface for components to
  11. * cache and retrieve data from a local JavaScript struct.
  12. *
  13. * @module cache
  14. * @main
  15. */
  16. /**
  17. * Provides the base class for the YUI Cache utility.
  18. *
  19. * @submodule cache-base
  20. */
  21. var LANG = Y.Lang,
  22. isDate = Y.Lang.isDate,
  23. /**
  24. * Base class for the YUI Cache utility.
  25. * @class Cache
  26. * @extends Base
  27. * @constructor
  28. */
  29. Cache = function() {
  30. Cache.superclass.constructor.apply(this, arguments);
  31. };
  32. /////////////////////////////////////////////////////////////////////////////
  33. //
  34. // Cache static properties
  35. //
  36. /////////////////////////////////////////////////////////////////////////////
  37. Y.mix(Cache, {
  38. /**
  39. * Class name.
  40. *
  41. * @property NAME
  42. * @type String
  43. * @static
  44. * @final
  45. * @value "cache"
  46. */
  47. NAME: "cache",
  48. ATTRS: {
  49. /////////////////////////////////////////////////////////////////////////////
  50. //
  51. // Cache Attributes
  52. //
  53. /////////////////////////////////////////////////////////////////////////////
  54. /**
  55. * @attribute max
  56. * @description Maximum number of entries the Cache can hold.
  57. * Set to 0 to turn off caching.
  58. * @type Number
  59. * @default 0
  60. */
  61. max: {
  62. value: 0,
  63. setter: "_setMax"
  64. },
  65. /**
  66. * @attribute size
  67. * @description Number of entries currently cached.
  68. * @type Number
  69. */
  70. size: {
  71. readOnly: true,
  72. getter: "_getSize"
  73. },
  74. /**
  75. * @attribute uniqueKeys
  76. * @description Validate uniqueness of stored keys. Default is false and
  77. * is more performant.
  78. * @type Boolean
  79. */
  80. uniqueKeys: {
  81. value: false
  82. },
  83. /**
  84. * @attribute expires
  85. * @description Absolute Date when data expires or
  86. * relative number of milliseconds. Zero disables expiration.
  87. * @type Date | Number
  88. * @default 0
  89. */
  90. expires: {
  91. value: 0,
  92. validator: function(v) {
  93. return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
  94. }
  95. },
  96. /**
  97. * @attribute entries
  98. * @description Cached entries.
  99. * @type Array
  100. */
  101. entries: {
  102. readOnly: true,
  103. getter: "_getEntries"
  104. }
  105. }
  106. });
  107. Y.extend(Cache, Y.Base, {
  108. /////////////////////////////////////////////////////////////////////////////
  109. //
  110. // Cache private properties
  111. //
  112. /////////////////////////////////////////////////////////////////////////////
  113. /**
  114. * Array of request/response objects indexed chronologically.
  115. *
  116. * @property _entries
  117. * @type Object[]
  118. * @private
  119. */
  120. _entries: null,
  121. /////////////////////////////////////////////////////////////////////////////
  122. //
  123. // Cache private methods
  124. //
  125. /////////////////////////////////////////////////////////////////////////////
  126. /**
  127. * @method initializer
  128. * @description Internal init() handler.
  129. * @param config {Object} Config object.
  130. * @private
  131. */
  132. initializer: function(config) {
  133. /**
  134. * @event add
  135. * @description Fired when an entry is added.
  136. * @param e {Event.Facade} Event Facade with the following properties:
  137. * <dl>
  138. * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
  139. * </dl>
  140. * @preventable _defAddFn
  141. */
  142. this.publish("add", {defaultFn: this._defAddFn});
  143. /**
  144. * @event flush
  145. * @description Fired when the cache is flushed.
  146. * @param e {Event.Facade} Event Facade object.
  147. * @preventable _defFlushFn
  148. */
  149. this.publish("flush", {defaultFn: this._defFlushFn});
  150. /**
  151. * @event request
  152. * @description Fired when an entry is requested from the cache.
  153. * @param e {Event.Facade} Event Facade with the following properties:
  154. * <dl>
  155. * <dt>request (Object)</dt> <dd>The request object.</dd>
  156. * </dl>
  157. */
  158. /**
  159. * @event retrieve
  160. * @description Fired when an entry is retrieved from the cache.
  161. * @param e {Event.Facade} Event Facade with the following properties:
  162. * <dl>
  163. * <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
  164. * </dl>
  165. */
  166. // Initialize internal values
  167. this._entries = [];
  168. },
  169. /**
  170. * @method destructor
  171. * @description Internal destroy() handler.
  172. * @private
  173. */
  174. destructor: function() {
  175. this._entries = [];
  176. },
  177. /////////////////////////////////////////////////////////////////////////////
  178. //
  179. // Cache protected methods
  180. //
  181. /////////////////////////////////////////////////////////////////////////////
  182. /**
  183. * Sets max.
  184. *
  185. * @method _setMax
  186. * @protected
  187. */
  188. _setMax: function(value) {
  189. // If the cache is full, make room by removing stalest element (index=0)
  190. var entries = this._entries;
  191. if(value > 0) {
  192. if(entries) {
  193. while(entries.length > value) {
  194. entries.shift();
  195. }
  196. }
  197. }
  198. else {
  199. value = 0;
  200. this._entries = [];
  201. }
  202. return value;
  203. },
  204. /**
  205. * Gets size.
  206. *
  207. * @method _getSize
  208. * @protected
  209. */
  210. _getSize: function() {
  211. return this._entries.length;
  212. },
  213. /**
  214. * Gets all entries.
  215. *
  216. * @method _getEntries
  217. * @protected
  218. */
  219. _getEntries: function() {
  220. return this._entries;
  221. },
  222. /**
  223. * Adds entry to cache.
  224. *
  225. * @method _defAddFn
  226. * @param e {Event.Facade} Event Facade with the following properties:
  227. * <dl>
  228. * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
  229. * </dl>
  230. * @protected
  231. */
  232. _defAddFn: function(e) {
  233. var entries = this._entries,
  234. max = this.get("max"),
  235. entry = e.entry;
  236. if(this.get("uniqueKeys") && (this.retrieve(e.entry.request))) {
  237. entries.shift();
  238. }
  239. // If the cache at or over capacity, make room by removing stalest element (index=0)
  240. while(max && entries.length>=max) {
  241. entries.shift();
  242. }
  243. // Add entry to cache in the newest position, at the end of the array
  244. entries[entries.length] = entry;
  245. },
  246. /**
  247. * Flushes cache.
  248. *
  249. * @method _defFlushFn
  250. * @param e {Event.Facade} Event Facade object.
  251. * @protected
  252. */
  253. _defFlushFn: function(e) {
  254. var entries = this._entries,
  255. details = e.details[0],
  256. pos;
  257. //passed an item, flush only that
  258. if(details && LANG.isValue(details.request)) {
  259. pos = this._position(details.request);
  260. if(LANG.isValue(pos)) {
  261. entries.splice(pos,1);
  262. }
  263. }
  264. //no item, flush everything
  265. else {
  266. this._entries = [];
  267. }
  268. },
  269. /**
  270. * Default overridable method compares current request with given cache entry.
  271. * Returns true if current request matches the cached request, otherwise
  272. * false. Implementers should override this method to customize the
  273. * cache-matching algorithm.
  274. *
  275. * @method _isMatch
  276. * @param request {Object} Request object.
  277. * @param entry {Object} Cached entry.
  278. * @return {Boolean} True if current request matches given cached request, false otherwise.
  279. * @protected
  280. */
  281. _isMatch: function(request, entry) {
  282. if(!entry.expires || new Date() < entry.expires) {
  283. return (request === entry.request);
  284. }
  285. return false;
  286. },
  287. /**
  288. * Returns position of a request in the entries array, otherwise null.
  289. *
  290. * @method _position
  291. * @param request {Object} Request object.
  292. * @return {Number} Array position if found, null otherwise.
  293. * @protected
  294. */
  295. _position: function(request) {
  296. // If cache is enabled...
  297. var entries = this._entries,
  298. length = entries.length,
  299. i = length-1;
  300. if((this.get("max") === null) || this.get("max") > 0) {
  301. // Loop through each cached entry starting from the newest
  302. for(; i >= 0; i--) {
  303. // Execute matching function
  304. if(this._isMatch(request, entries[i])) {
  305. return i;
  306. }
  307. }
  308. }
  309. return null;
  310. },
  311. /////////////////////////////////////////////////////////////////////////////
  312. //
  313. // Cache public methods
  314. //
  315. /////////////////////////////////////////////////////////////////////////////
  316. /**
  317. * Adds a new entry to the cache of the format
  318. * {request:request, response:response, cached:cached, expires:expires}.
  319. * If cache is full, evicts the stalest entry before adding the new one.
  320. *
  321. * @method add
  322. * @param request {Object} Request value.
  323. * @param response {Object} Response value.
  324. */
  325. add: function(request, response) {
  326. var expires = this.get("expires");
  327. if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
  328. (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
  329. this.fire("add", {entry: {
  330. request:request,
  331. response:response,
  332. cached: new Date(),
  333. expires: isDate(expires) ? expires :
  334. (expires ? new Date(new Date().getTime() + this.get("expires")) : null)
  335. }});
  336. }
  337. else {
  338. }
  339. },
  340. /**
  341. * Flushes cache.
  342. *
  343. * @method flush
  344. */
  345. flush: function(request) {
  346. this.fire("flush", { request: (LANG.isValue(request) ? request : null) });
  347. },
  348. /**
  349. * Retrieves cached object for given request, if available, and refreshes
  350. * entry in the cache. Returns null if there is no cache match.
  351. *
  352. * @method retrieve
  353. * @param request {Object} Request object.
  354. * @return {Object} Cached object with the properties request and response, or null.
  355. */
  356. retrieve: function(request) {
  357. // If cache is enabled...
  358. var entries = this._entries,
  359. length = entries.length,
  360. entry = null,
  361. pos;
  362. if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
  363. this.fire("request", {request: request});
  364. pos = this._position(request);
  365. if(LANG.isValue(pos)) {
  366. entry = entries[pos];
  367. this.fire("retrieve", {entry: entry});
  368. // Refresh the position of the cache hit
  369. if(pos < length-1) {
  370. // Remove element from its original location
  371. entries.splice(pos,1);
  372. // Add as newest
  373. entries[entries.length] = entry;
  374. }
  375. return entry;
  376. }
  377. }
  378. return null;
  379. }
  380. });
  381. Y.Cache = Cache;
  382. }, '3.4.0' ,{requires:['base']});