npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

simple-file-cache

v1.0.0

Published

In-memory cache to improve performance of repeated reads when using FileReader in the browser

Readme

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 of window.Blob
    • result: a CachedBlob, with the same contents as the parameter, that can be used with the functions from simpleFileCache.api
  • simpleFileCache.createUncachedCopy(cachedBlob)
    • parameters:
      • pseudoBlob: a CachedBlob object generated using the functions from simpleFileCache.api
    • result: an instance of window.Blob with the same contents as the parameter
  • simpleFileCache.api.blob(): same as window.Blob, except it has a properSlice function instead of slice or webkitSlice, etc., and it operates exclusively on CachedBlob, CachedUInt8Array, etc. objects
  • simpleFileCache.api.fileReader(): same as window.FileReader, except it operates exclusively on CachedBlob, CachedUInt8Array, etc. objects
  • simpleFileCache.api.byteArray(): same as window.Uint8Array, except it operates exclusively on CachedBlob, 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.