on
Italy
- Get link
- X
- Other Apps
basket.js is a small JavaScript library supporting localStorage caching of scripts.This quote summaries very well the aim of this project. Once the library is loaded into the memory, then it sends asynchronously requests to retrieve the other scripts needed by the page. It injects them into the document and then caches them into the browser’s local storage. Doing so, the next time the page is loaded, the scripts will be loaded locally without performing any HTTP request.
localStorage
is much faster than browser cache. On SitePoint we have covered this topic recently with the article HTML5 Local Storage Revisited, where Luis Vieira also covered some of the limitation of localStorage
. In addition IndexedDB is (surprisingly) slower than localStorage
, both for reading and writing.basket.require()
: require remote scripts and inject them into the page (with or without caching them)basket.get()
: inspect localStorage
for scriptsbasket.remove()
: remove a cached scriptbasket.clear()
: remove all cached scriptsbasket.require({ url: 'jquery.js' });
This method can be used to require one or more scripts with one call.
It takes a variable number of arguments, one object for each script.
You can also pass fields for the scripts’ URL and a few options for each
script. The call always return a promise. This promise is fulfilled
once the script is loaded, or rejected on error. This is convenient for
several reasons:.get()
at a later point, if you actually need itbasket.require(
{ url: 'jquery.js' },
{ url: 'underscore.js' },
{ url: 'backbone.js' }
);
Otherwise, basket.js
‘ promise-oriented API makes your life easy:basket
.require({ url: 'jquery.js' })
.then(function () {
basket.require({ url: 'jquery-ui.js' });
});
basket.require(
// Expires in 2 hours
{ url: 'jquery.js', expire: 2 },
// Expires in 3 days
{ url: 'underscore.js', expire: 72 },
// It's not cached at all
{ url: 'backbone.js', skipCache: true },
// If you later change this value the older version from cache will be ignored
{ url: 'd3.js', unique: 'v1.1.0' }
);
basket
.remove('jquery.js')
.remove('modernizr');
Or, you can remove only the expired items, all at once, without explicitly listing themremove basket.clear(true);
Finally, it’s also possible to clear all the scripts for your page:remove basket.clear();
basket.isValidateItem
with a function that returns true
when the cached item is valid, and false
when the script has to be loaded from source again.expiry
and unique
options, but adds on top of it. Moreover, even if overwriting isValidateItem
is a powerful option, it’s unlikely you will really need it, ever. basket.js
to refactor scripts loading for TubeHound, replacing RequireJS as a script manager.requirejs.config({
"baseUrl”: "js/",
"paths": {
"jquery": "./lib/jquery-2.0.3.min",
"Ractive": "./lib/Ractive",
"utility": "utility",
"fly": "./lib/Ractive-transitions-fly",
"fade": "./lib/Ractive-transitions-fade",
"bootstrap": "./lib/bootstrap.min",
"jquery-ui": "./lib/jquery-ui-1.10.4.custom.min",
"jquery-contextmenu": "./lib/jquery.contextmenu"
},
"shim": {
"jquery": {
exports: 'jquery'
},
"Ractive": {
exports: 'Ractive'
},
"utility": {
deps: ['jquery'],
exports: 'utility'
},
"bootstrap": {
deps: ['jquery'],
exports: 'bootstrap'
},
"jquery-ui": {
deps: ['jquery'],
exports: 'jquery-ui'
},
"jquery-contextmenu": {
deps: ['jquery'],
exports: 'jquery-contextmenu'
}
}
});
require([
'jquery',
'Ractive',
'utility',
'bootstrap',
'fly',
'jquery-ui',
'jquery-contextmenu',
'fade'
], function ($, Ractive, utility) {
...
});
Now I removed all of that except for the function declaration,
stripped of all its arguments. Then I added a new small script called loading.js
:(function () {
function requireScriptsDependingOnJQueryAndRactive () {
return basket.require(
{ url: 'js/lib/bootstrap.min.js'},
{ url: 'js/lib/Ractive-transitions-fly.js', key: 'fly' },
{ url: 'js/lib/Ractive-transitions-fade.js', key: 'fade' },
{ url: 'js/lib/jquery-ui-1.10.4.custom.min.js', key: 'jquery-ui' },
{ url: 'js/lib/jquery.contextmenu.js', key: 'jquery-contextmenu' },
{ url: 'js/utility.min.js', key: 'utility', unique: 1 }
);
}
basket.require(
{ url: 'js/lib/jquery-2.0.3.min.js', key: 'jquery' },
{ url: 'js/lib/Ractive.js', key: 'Ractive' }
).then(requireScriptsDependingOnJQueryAndRactive)
.then(function () {
basket.require({ url: 'js/thound.min.js', unique: 1 }); //unique is to make sure we can force a reload, in case of bugs
});
}());
This is now loaded via the
tag in the HTML page (right after basket.js
):
utility.js
. Before, there was some plumbing needed by RequireJS:requirejs.config({
"baseUrl": "js/",
"paths": {
"jquery": "./lib/jquery-2.0.3.min"
},
"shim": {
"jquery": {
exports: 'jquery'
}
}
});
define([
'jquery'
], function ($) {
"use strict";
...
});
After, I “export” the module using a global variable as shown below:var utility = (function () {
"use strict";
...
}());
localStorage
: the delta will measure the actual gain provided by caching scripts.basket.js
, the page can be loaded in 771ms, and only 5.3KB are actually loaded (17 requests, mostly served from cache).localStorage
are totally understandable. It’s trying to improve performance, and experience has shown that localStorage
is the fastest solution available.localStorage
are not going away any time soon, at least not for Chrome, where augmenting the quota would require some non-trivial rewriting.basket.js
‘ authors are considering several alternatives, including a tiered solution that will try to use the best persistence API available on the browser: Service Workers, Cache API (on Chrome), or FileSystem API.require()
method: all I got was a generic TypeError
from the lib’s code, so it took me a lot of trials and errors to realize my mistake.basker.require
) inside a callback along the promises chain. Since your error message gets swallowed, it will take you some time to realize it.basket.js
only in production, when optimization is needed.basket.js
is a very promising idea, and the results looks really good – but my
take is it needs a little extra step to be ready to be used for the
development of a complex project – or in production for a huge page.
(This would be true for any project that has not reached version 1, due
to possible changes in its interface/structure).
Comments
Post a Comment