simple-file-cache ReadMe
Introduction
simple-file-cache is a simple in-memory cache to improve performance when reading files using the HTML5 FileReader
API. Performance improvements can be observed on all browsers, but are most dramatic with Chrome and Safari. For instance, these times to complete a moderately complex workload were observed:
- on desktop Chrome:
- 40 seconds (without simple-file-cache)
- 3 seconds (with simple-file-cache)
- on mobile Chrome (Samsung Galaxy S II):
- 200 seconds (without simple-file-cache)
- 20 seconds (with simple-file-cache)
- on desktop Safari:
- 15 seconds (without simple-file-cache)
- 1 second (with simple-file-cache)
- on desktop Firefox:
- 20 seconds (without simple-file-cache)
- 2 seconds (with simple-file-cache)
(lower times are better, obviously)
Dependencies
A browser environment with the asynchronous FileReader
API.
Usage
simple-file-cache needs to be included in the web page before the code that wants to use it (it should be possible to use browserify to have it work with require()
instead, though I have not tried).
Its entry point is the simpleFileCacheLoader()
function, but its dependencies need to be injected, which is best done by using this sample code:
var prefixator = function (apiobject, memberFuncName, prefixArray) {
var result = undefined;
var daFunc = apiobject[memberFuncName];
if (daFunc) {
return {
prefix: '',
obj: daFunc
};
}
var capMFC = memberFuncName.charAt(0).toUpperCase() + memberFuncName.slice(1);
try {
prefixArray.forEach(function (element) {
daFunc = apiobject[element + capMFC];
if (daFunc) {
result = {
prefix: element,
obj: daFunc
};
throw {
name: 'BreakFromForEachException',
message: 'Exception to end array enumeration prematurely'
};
}
});
} catch (e) {
if (e.name !== 'BreakFromForEachException') { // rethrow
throw e;
}
// otherwise, just swallow our exception
}
// if none was found, this will return undefined
return result;
};
var installProperSlice = function (obj) {
return obj;
};
(function () {
var temp = function (obj) {
var cached_imp = prefixator(obj, "slice", ["webkit", "moz"]).obj;
obj.properSlice = function () {
return installProperSlice(cached_imp.apply(obj, arguments));
};
return obj;
};
installProperSlice = temp;
}());
var simpleFileCache = simpleFileCacheLoader({
EMPTY: 0,
LOADING: 1,
DONE: 2,
"blob": function (param1, param2) {
var new_blob = null;
// utterly silly impedance mismatch (I tried Function.prototype.bind.apply without success: TypeError)
if (param2 === undefined) {
new_blob = new window.Blob(param1);
} else {
new_blob = new window.Blob(param1, param2);
}
return installProperSlice(new_blob);
},
"fileReader": function () {
return new window.FileReader();
},
"byteArray": function (param) {
return new window.Uint8Array(param);
}});
After that, all functionality is accessed through the simpleFileCache object:
-
simpleFileCache.createCachedCopy(blob)
- parameters:
-
blob
: an instance ofwindow.Blob
-
- result: a
CachedBlob
, with the same contents as the parameter, that can be used with the functions fromsimpleFileCache.api
- parameters:
-
simpleFileCache.createUncachedCopy(cachedBlob)
- parameters:
-
pseudoBlob
: aCachedBlob
object generated using the functions fromsimpleFileCache.api
-
- result: an instance of
window.Blob
with the same contents as the parameter
- parameters:
-
simpleFileCache.api.blob()
: same aswindow.Blob
, except it has aproperSlice
function instead ofslice
orwebkitSlice
, etc., and it operates exclusively onCachedBlob
,CachedUInt8Array
, etc. objects -
simpleFileCache.api.fileReader()
: same aswindow.FileReader
, except it operates exclusively onCachedBlob
,CachedUInt8Array
, etc. objects -
simpleFileCache.api.byteArray()
: same aswindow.Uint8Array
, except it operates exclusively onCachedBlob
,CachedUInt8Array
, etc. objects
The principle is that simpleFileCache.api
is meant to be passed to a module that itself expects FileReader
to be injected, such that the module does not even have to know it is using the simple-file-cache API. You can see how this is used in the JPS project, which you can think of as the simple-file-cache example usage code.
In particular, it allows simple-file-cache to be easily taken out: just inject the FileReader API instead of the simple-file-cache API, and you're back to using FileReader directly. This will be useful the day browsers will finally fix this performance issue and render simple-file-cache unnecessary.
Note that you cannot mix the FileReader
API with the simpleFileCache.api
: for instance, you cannot use an instance generated by window.FileReader
to read a CachedBlob
: you must get a Blob
from it first, using simpleFileCache.createUncachedCopy(cachedBlob)
.
Tests
Open test_harness/main.html
with any browser (no support for FileReader is even required) to execute the self-tests.
Reporting Bugs
Email me if you find anything.
Support
simple-file-cache is free to use and modify (under the terms of the BSD license). If you find it useful, I request that you consider donating to the ACLU and the UNHCR, however.