Skip to content

Instantly share code, notes, and snippets.

@peol
Forked from addyosmani/docs.md
Created March 9, 2012 16:54
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save peol/2007484 to your computer and use it in GitHub Desktop.
Save peol/2007484 to your computer and use it in GitHub Desktop.
basket.js docs

##basket.js 0.2

###Introduction

basket.js is a small JavaScript library supporting localStorage caching of scripts. If script(s) have previously been saved locally, they will simply be loaded and injected into the current document. If not, they will be XHR'd in for use right away, but cached so that no additional loads are required in the future.

###Why localStorage?

Tests by Bing and Google have shown that there are performance benefits to caching assets in localStorage (especially on mobile) when compared to simply reading and writing from the standard browser cache. This project is currently working on replicating these tests in the public so that we have definitive statistics on whether this is true.

Developers have also been wondering why we opted for localStorage as opposed to alternatives such as IndexedDB. Jens Arps has shown that IDB is at present significantly slower than localStorage for reading and writing assets. Other developers exploring this space have also shown that localStorage works just fine for caching data (it's actually significantly faster in Safari at the moment than any other browser).

We believe that in time, once implementers have optimized localStorage for use cases such as file storage, it will become more feasible to use cross-browser. In the mean time, we are also exploring solutions such as the FileSystem API as a storage mechanism for caching scripts locally.

###Project History

This project was created as a response to a tweet by Steve Souders asking that the jQuery project consider caching jQuery in localStorage for performance reasons. Intrigued by the idea, we began exploring a minimalist solution to it (just for the sake of experimentation).

You may remember Souders previously did research and a write-up on search engines making use of localStorage caching back in 2011. His conclusions were:

Bing and Google Search make extensive use of localStorage for stashing SCRIPT blocks that are used on subsequent page views. None of the other top sites from my previous post use localStorage in this way. Are Bing and Google Search onto something? Yes, definitely.

To help provide a more general solution for this problem, we put together a script loader that treats localStorage as a cache.

###Compatibility

basket.js supports locally caching scripts in any browser with localStorage capabilities. For a complete list of supported browsers, see here.

###API And Examples

Let's briefly review the current basket.js API, which differs from the API supported in 0.1.

  • basket.require()
  • basket.add()
  • basket.remove()
  • basket.wait()

basket.require( uri )

uri: A relative URI to a local script to load.

.require() allows us to construct loader chains, each of which instruct basket.js to fetch (either externally or from a localStorage cached-copy) a script defined by a supplied uri. The basic loading of a single uri could be achieved as follows:

basket.require('jquery.js');

This will check to see if an item with the key basket-jquery.js exists in localStorage (i.e a cached copy of the script). If present, the script contents are read from storage and injected into the current page. If not present, the script will be fetched, cached in storage and then similarly injected into the document for use.

basket.js also supports chaining and so requesting multiple scripts is also straight-forward:

basket
    .require('jquery.js')
    .require('underscore.js')
    .require('backbone.js');

basket.require( key )

If a script has been saved to a specific key in localStorage (e.g jquery), it can be accessed using .require() as follows:

basket.require('jquery');

Note that at present, JSONP/server-side middleware is necessary for the support of remote scripts. This is down to access of script content being limited under cross-origin policies.

basket.add( uri, [,options], [,callback] )

uri: A relative URI to a local script to be saved to localStorage (but not executed)

options: An object allowing you to configure the add operation. It supports two optional keys: overwrite - A boolean defining whether an entry being added can overwrite an existing entry with the same path/filename.

key: A key-name under which to save a specific script callback: An optional function to be executed once a script has been added to localStorage

.add() allows you to add scripts to localStorage without actually injecting them into the current document. It accepts a URI, which it then fetches the contents of and caches. If the overwrite argument is supplied (and is true), basket.js will overwrite an existing entry for the script being added if one is found.

basket
	.add('jquery.js')
	.add('handlebars.js')
	.add('jquery.plugin1.js')
	.add('jquery.plugin2.js');

An example of how to use the callback is as follows:

basket
	.add('jquery.js')
	.add('handlebars.js', {}, function(){
		console.log('jQuery and Handlebars exist in localStorage now');
	});

If you wish to store a script under a specific key name (e.g if you have a build process outputting a script of a name such as 012345.js and would like to store it under say, main), this could be done as follows:

basket.add('012345.js', { key: 'main' });
```

Similarly, if you wish to store `jquery-1.7.1.min.js` as `jquery`, this can be done as well:

```javascript 
basket.add('jquery-1.7.1.min.js', { key: 'jquery' });
```

Finally if you would like to use options it is fairly trivial to add a script with an option to overwrite it if it already exists, store it under a specific key and add a callback to it as follows:

```javascript
basket.add('jquery-1.7.1', { key: 'foo', overwrite: false }, function() {
});
```

**basket.remove( uri )**

*uri:* A relative URI to a local script to be removed from localStorage

`.remove()` will simply remove a previously cached script from localStorage. An example of how to use it can be seen below:

```javascript
basket
	.remove('jquery.js')
	.remove('modernizr.js');
```

**basket.remove( key )**

If a script has been saved to a specific key in localStorage (e.g `jquery`), it can be removed using `.remove()` as follows:

```javascript
basket.remove("jquery");
```

**basket.wait( [,callback] )**

*callback:* An optional function to be executed once a script has loaded

When `.wait()` is inserted into a chain, it informs the chain to ensure previous scripts inserted into the chain complete their loading prior to allowing the next item to load and execute. At its most basic, `.wait()` can be used as follows:

```javascript
basket
	.require('jquery.js').wait()
	.require('jquery.plugin1.js')
	.require('jquery.plugin2.js');
```

You can also specify an (optional) callback (typically an anonymous function) that will be executed in order following the previous scripts executing and before subsequent scripts in the chain are executed.

```javascript
basket
	.require('jquery.js')
	.require('underscore.js')
	.require('app.js').wait(function(){

		var numbers = [10, 5, 100, 2, 1000];
		$('#message')
			.html('Live long and prosper, bro.
			Want the minimum value in our array? Boom:' + _.min(numbers));

	});
```

Finally, in case you're interested, here's the basket.js example that was used to power the intro to this page:

```javascript
var message, str;
basket
	.require('test/jquery-1.7.1.min.js').wait()
	.require('test/underscore-min.js')
	.require('test/backbone-min.js').wait(function() {

		// Backbone is now available, so let's define
		// a test model with a sample attribute

		var testModel = Backbone.Model.extend({
		  idAttribute: '_id'
		});

		// Create an instance of the model
		var myModel = new testModel({ _id: 4, name: 'Nyan Cat' });

		// Cache a reference to our message holder with jQuery
		message = $('#message');

		// Where #intro contains a template, get our templating on:

		var templateContent = $('#intro').html();
		var compiled = _.template(templateContent);
		message.html( compiled({name: myModel.get('name')}));

	});
```	
 
basket.js is released under an MIT/GPL license and is currently maintained by [Addy Osmani](http://github.com/addyosmani), [Sindre Sorhus](http://github.com/sindresorhus) and [Andrée Hansson](http://github.com/peol).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment