Version 3.18.1

APIs

  • Begin typing in the search box above to see results.
Show:

File: cache/js/cache-base.js

 /**
 * The Cache utility provides a common configurable interface for components to
 * cache and retrieve data from a local JavaScript struct.
 *
 * @module cache
 * @main
 */
 
 /**
 * Provides the base class for the YUI Cache utility.
 *
 * @submodule cache-base
 */
 var LANG = Y.Lang,
 isDate = Y.Lang.isDate,
 
 /**
 * Base class for the YUI Cache utility.
 * @class Cache
 * @extends Base
 * @constructor
 */
 Cache = function() {
 Cache.superclass.constructor.apply(this, arguments);
 };
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Cache static properties
 //
 /////////////////////////////////////////////////////////////////////////////
 Y.mix(Cache, {
 /**
 * Class name.
 *
 * @property NAME
 * @type String
 * @static
 * @final
 * @value "cache"
 */
 NAME: "cache",
 
 
 ATTRS: {
 /////////////////////////////////////////////////////////////////////////////
 //
 // Cache Attributes
 //
 /////////////////////////////////////////////////////////////////////////////
 
 /**
 * @attribute max
 * @description Maximum number of entries the Cache can hold.
 * Set to 0 to turn off caching.
 * @type Number
 * @default 0
 */
 max: {
 value: 0,
 setter: "_setMax"
 },
 
 /**
 * @attribute size
 * @description Number of entries currently cached.
 * @type Number
 */
 size: {
 readOnly: true,
 getter: "_getSize"
 },
 
 /**
 * @attribute uniqueKeys
 * @description Validate uniqueness of stored keys. Default is false and
 * is more performant.
 * @type Boolean
 */
 uniqueKeys: {
 value: false
 },
 
 /**
 * @attribute expires
 * @description Absolute Date when data expires or
 * relative number of milliseconds. Zero disables expiration.
 * @type Date | Number
 * @default 0
 */
 expires: {
 value: 0,
 validator: function(v) {
 return Y.Lang.isDate(v) || (Y.Lang.isNumber(v) && v >= 0);
 }
 },
 
 /**
 * @attribute entries
 * @description Cached entries.
 * @type Array
 */
 entries: {
 readOnly: true,
 getter: "_getEntries"
 }
 }
 });
 
 Y.extend(Cache, Y.Base, {
 /////////////////////////////////////////////////////////////////////////////
 //
 // Cache private properties
 //
 /////////////////////////////////////////////////////////////////////////////
 
 /**
 * Array of request/response objects indexed chronologically.
 *
 * @property _entries
 * @type Object[]
 * @private
 */
 _entries: null,
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Cache private methods
 //
 /////////////////////////////////////////////////////////////////////////////
 
 /**
 * @method initializer
 * @description Internal init() handler.
 * @param config {Object} Config object.
 * @private
 */
 initializer: function(config) {
 
 /**
 * @event add
 * @description Fired when an entry is added.
 * @param e {EventFacade} Event Facade with the following properties:
 * <dl>
 * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
 * </dl>
 * @preventable _defAddFn
 */
 this.publish("add", {defaultFn: this._defAddFn});
 
 /**
 * @event flush
 * @description Fired when the cache is flushed.
 * @param e {EventFacade} Event Facade object.
 * @preventable _defFlushFn
 */
 this.publish("flush", {defaultFn: this._defFlushFn});
 
 /**
 * @event request
 * @description Fired when an entry is requested from the cache.
 * @param e {EventFacade} Event Facade with the following properties:
 * <dl>
 * <dt>request (Object)</dt> <dd>The request object.</dd>
 * </dl>
 */
 
 /**
 * @event retrieve
 * @description Fired when an entry is retrieved from the cache.
 * @param e {EventFacade} Event Facade with the following properties:
 * <dl>
 * <dt>entry (Object)</dt> <dd>The retrieved entry.</dd>
 * </dl>
 */
 
 // Initialize internal values
 this._entries = [];
 Y.log("Cache initialized", "info", "cache");
 },
 
 /**
 * @method destructor
 * @description Internal destroy() handler.
 * @private
 */
 destructor: function() {
 this._entries = [];
 Y.log("Cache destroyed", "info", "cache");
 },
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Cache protected methods
 //
 /////////////////////////////////////////////////////////////////////////////
 
 /**
 * Sets max.
 *
 * @method _setMax
 * @protected
 */
 _setMax: function(value) {
 // If the cache is full, make room by removing stalest element (index=0)
 var entries = this._entries;
 if(value > 0) {
 if(entries) {
 while(entries.length > value) {
 entries.shift();
 }
 }
 }
 else {
 value = 0;
 this._entries = [];
 }
 return value;
 },
 
 /**
 * Gets size.
 *
 * @method _getSize
 * @protected
 */
 _getSize: function() {
 return this._entries.length;
 },
 
 /**
 * Gets all entries.
 *
 * @method _getEntries
 * @protected
 */
 _getEntries: function() {
 return this._entries;
 },
 
 
 /**
 * Adds entry to cache.
 *
 * @method _defAddFn
 * @param e {EventFacade} Event Facade with the following properties:
 * <dl>
 * <dt>entry (Object)</dt> <dd>The cached entry.</dd>
 * </dl>
 * @protected
 */
 _defAddFn: function(e) {
 var entries = this._entries,
 entry = e.entry,
 max = this.get("max"),
 pos;
 
 // If uniqueKeys is true and item exists with this key, then remove it.
 if (this.get("uniqueKeys")) {
 pos = this._position(e.entry.request);
 if (LANG.isValue(pos)) {
 entries.splice(pos, 1);
 }
 }
 
 // If the cache at or over capacity, make room by removing stalest
 // element(s) starting at index-0.
 while (max && entries.length >= max) {
 entries.shift();
 }
 
 // Add entry to cache in the newest position, at the end of the array
 entries[entries.length] = entry;
 Y.log("Cached entry: " + Y.dump(entry), "info", "cache");
 },
 
 /**
 * Flushes cache.
 *
 * @method _defFlushFn
 * @param e {EventFacade} Event Facade object.
 * @protected
 */
 _defFlushFn: function(e) {
 var entries = this._entries,
 details = e.details[0],
 pos;
 
 //passed an item, flush only that
 if(details && LANG.isValue(details.request)) {
 pos = this._position(details.request);
 
 if(LANG.isValue(pos)) {
 entries.splice(pos,1);
 
 Y.log("Flushed cache item " + Y.dump(details.request), "info", "cache");
 }
 }
 //no item, flush everything
 else {
 this._entries = [];
 Y.log("Cache flushed", "info", "cache");
 }
 },
 
 /**
 * Default overridable method compares current request with given cache entry.
 * Returns true if current request matches the cached request, otherwise
 * false. Implementers should override this method to customize the
 * cache-matching algorithm.
 *
 * @method _isMatch
 * @param request {Object} Request object.
 * @param entry {Object} Cached entry.
 * @return {Boolean} True if current request matches given cached request, false otherwise.
 * @protected
 */
 _isMatch: function(request, entry) {
 if(!entry.expires || new Date() < entry.expires) {
 return (request === entry.request);
 }
 return false;
 },
 
 /**
 * Returns position of a request in the entries array, otherwise null.
 *
 * @method _position
 * @param request {Object} Request object.
 * @return {Number} Array position if found, null otherwise.
 * @protected
 */
 _position: function(request) {
 // If cache is enabled...
 var entries = this._entries,
 length = entries.length,
 i = length-1;
 
 if((this.get("max") === null) || this.get("max") > 0) {
 // Loop through each cached entry starting from the newest
 for(; i >= 0; i--) {
 // Execute matching function
 if(this._isMatch(request, entries[i])) {
 return i;
 }
 }
 }
 
 return null;
 },
 
 /////////////////////////////////////////////////////////////////////////////
 //
 // Cache public methods
 //
 /////////////////////////////////////////////////////////////////////////////
 
 /**
 * Adds a new entry to the cache of the format
 * {request:request, response:response, cached:cached, expires:expires}.
 * If cache is full, evicts the stalest entry before adding the new one.
 *
 * @method add
 * @param request {Object} Request value.
 * @param response {Object} Response value.
 */
 add: function(request, response) {
 var expires = this.get("expires");
 if(this.get("initialized") && ((this.get("max") === null) || this.get("max") > 0) &&
 (LANG.isValue(request) || LANG.isNull(request) || LANG.isUndefined(request))) {
 this.fire("add", {entry: {
 request:request,
 response:response,
 cached: new Date(),
 expires: isDate(expires) ? expires :
 (expires ? new Date(new Date().getTime() + this.get("expires")) : null)
 }});
 }
 else {
 Y.log("Could not add " + Y.dump(response) + " to cache for " + Y.dump(request), "info", "cache");
 }
 },
 
 /**
 * Flushes cache.
 *
 * @method flush
 */
 flush: function(request) {
 this.fire("flush", { request: (LANG.isValue(request) ? request : null) });
 },
 
 /**
 * Retrieves cached object for given request, if available, and refreshes
 * entry in the cache. Returns null if there is no cache match.
 *
 * @method retrieve
 * @param request {Object} Request object.
 * @return {Object} Cached object with the properties request and response, or null.
 */
 retrieve: function(request) {
 // If cache is enabled...
 var entries = this._entries,
 length = entries.length,
 entry = null,
 pos;
 
 if((length > 0) && ((this.get("max") === null) || (this.get("max") > 0))) {
 this.fire("request", {request: request});
 
 pos = this._position(request);
 
 if(LANG.isValue(pos)) {
 entry = entries[pos];
 
 this.fire("retrieve", {entry: entry});
 
 // Refresh the position of the cache hit
 if(pos < length-1) {
 // Remove element from its original location
 entries.splice(pos,1);
 // Add as newest
 entries[entries.length] = entry;
 Y.log("Refreshed cache entry: " + Y.dump(entry) +
 " for request: " + Y.dump(request), "info", "cache");
 }
 
 Y.log("Retrieved cached response: " + Y.dump(entry) +
 " for request: " + Y.dump(request), "info", "cache");
 return entry;
 }
 }
 return null;
 }
 });
 
 Y.Cache = Cache;
 
 

AltStyle によって変換されたページ (->オリジナル) /