$.cachedGetScript( url, callback1 );
$.cachedGetScript( url, callback2 );
缓存机制需要确保 脚本不管是否已经存在于缓存,只能被请求一次。 因此,为了缓存系统可以正确地处理请求,我们最终需要写出一些逻辑来跟踪绑定到给定url上的回调。
值得庆幸的是,这恰好是deferred所实现的那种逻辑,因此我们可以这样来做:
复制代码 代码如下:
var cachedScriptPromises = {};
$.cachedGetScript = function( url, callback ) {
if ( !cachedScriptPromises[ url ] ) {
cachedScriptPromises[ url ] = $.Deferred(function( defer ) {
$.getScript( url ).then( defer.resolve, defer.reject );
}).promise();
}
return cachedScriptPromises[ url ].done( callback );
};
代码相当简单:我们为每一个url缓存一个promise对象。 如果给定的url没有promise,我们创建一个deferred,并发出请求。 如果它已经存在我们只需要为它绑定回调。 该解决方案的一大优势是,它会透明地处理新的和缓存过的请求。 另一个优点是一个基于deferred的缓存 会优雅地处理失败情况。 当promise以‘rejected'状态结束的话,我们可以提供一个错误回调来测试:
$.cachedGetScript( url ).then( successCallback, errorCallback );
请记住:无论请求是否缓存过,上面的代码段都会正常运作!
通用异步缓存
为了使代码尽可能的通用,我们建立一个缓存工厂并抽象出实际需要执行的任务:
复制代码 代码如下:
$.createCache = function( requestFunction ) {
var cache = {};
return function( key, callback ) {
if ( !cache[ key ] ) {
cache[ key ] = $.Deferred(function( defer ) {
requestFunction( defer, key );
}).promise();
}
return cache[ key ].done( callback );
};
}
现在具体的请求逻辑已经抽象出来,我们可以重新写cachedGetScript:
复制代码 代码如下:
$.cachedGetScript = $.createCache(function( defer, url ) {
$.getScript( url ).then( defer.resolve, defer.reject );
});
每次调用createCache将创建一个新的缓存库,并返回一个新的高速缓存检索函数。现在,我们拥有了一个通用的缓存工厂,它很容易实现涉及从缓存中取值的逻辑场景。
图片加载
另一个候选场景是图像加载:确保我们不加载同一个图像两次,我们可能需要加载图像。 使用createCache很容易实现:
复制代码 代码如下:
$.loadImage = $.createCache(function( defer, url ) {
var image = new Image();
function cleanUp() {
image.onload = image.onerror = null;
}
defer.then( cleanUp, cleanUp );
image.onload = function() {
defer.resolve( url );
};
image.onerror = defer.reject;
image.src = url;
});
接下来的代码片段如下:
复制代码 代码如下:
$.loadImage( "my-image.png" ).done( callback1 );
$.loadImage( "my-image.png" ).done( callback2 );
无论image.png是否已经被加载,或者正在加载过程中,缓存都会正常工作。
缓存数据的API响应
哪些你的页面的生命周期过程中被认为是不可变的API请求,也是缓存完美的候选场景。 比如,执行以下操作:
复制代码 代码如下:
$.searchTwitter = $.createCache(function( defer, query ) {
$.ajax({
url: "http://search.twitter.com/search.json",
data: { q: query },
dataType: "jsonp",
success: defer.resolve,
error: defer.reject
});
});
程序允许你在Twitter上进行搜索,同时缓存它们:
复制代码 代码如下:
$.searchTwitter( "jQuery Deferred", callback1 );
$.searchTwitter( "jQuery Deferred", callback2 );
定时
基于deferred的缓存并不限定于网络请求;它也可以被用于定时目的。
例如,您可能需要在网页上给定一段时间后执行一个动作,来吸引用户对某个不容易引起注意的特定功能的关注或处理一个延时问题。 虽然setTimeout适合大多数用例,但在计时器出发后甚至理论上过期后就无法提供解决办法。 我们可以使用以下的缓存系统来处理:
复制代码 代码如下: