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 🙏

© 2024 – Pkg Stats / Ryan Hefner

hamster

v0.1.2

Published

The ultimate Javascript cache module. Cache the result of any function.

Downloads

11

Readme

Hamster

The ultimate Javascript cache module.
Unobtrusive and failsafe caching of anything.
Caches functions instead of data.

npm install hamster

But how?

var hamster = require('hamster');

// Cache a function
var getData = hamster(aFunctionThatTakesLotsOfTime);

// Call the function like you normally would
getData('yeah', resultHandler);

Advantages

  • Simple straight-forward API
  • No need to manage a cache object yourself
  • Easy to implement, no need to rewrite any function calls
  • Promotes separation of concerns
  • TTL-support, clear caches after a certain time
  • LRU-support, pop the least recently updated cache when reaching a max number of cached results
  • Pontentially supports any cache storage (for example redis)

TOC

Philosophy

When you cache a function using hamster(fn), a function is returned. You can use this function in exactly the same way as the original. No other part of your code should ever have to care about that the function is cached.

Also the cached function itself should not and need not be modified with caching in mind. The function should do what it does, callers should do what they do, while Hamster automagically takes care of the cache.

Note

Do not use Hamster with functions that are based on side-effects. That is, if it modifies an argument object or doesn't return the result, or if the result varies depending on non-argument variables (eg global vars or properties on its object).

A typical example of this would be trying to cache an express/connect middleware directly. That won't work since a middleware just modifies an object, that also is unique to every request. Instead, rewrite the function to only require what arguments it needs. For example:

// Do not:
app.use(hamster(getUserData));

// Do:
getUserData = hamster(function(id){...});

app.use(function (req, res, next) {
  getUserData(req.params.id, function (err, result) {
    req.user = result;
    next();
  });
});

Installation

npm install hamster

See releases for browserified source files.

API

hamster

A global instance of Hamster (see hamster() below).

hamster = new hamster.Hamster([options])

Creates a new instance of hamster with some customizable options (see options below).

cache = hamster(fn, [options])

An instance of Hamster, managing cached functions. Call it with a function to create a cache for that function. Returns a function that should replace the original function.

cache = hamster.sync()

A shorthand method for calling hamster(fn, { async: false }).

cache = hamster.async()

A shorthand method for calling hamster(fn, { async: true }).

cache()

Just use it as you would use the original function.

cache.original()

A reference to the original function, if you need to circumvent the cache.

cache.clear([key])

Clear all cached results (no key) or the result for a specific set of arguments.

Options

{
  async: true, // Set to false to enable caching synchronous functions
  ttl: 10000, // How long to wait before the cached result is cleared, in milliseconds
  maxSize: 50, // Max number of cached results, the least recently used will be dropped when exeeding this limit
  keys: [] // Possibility to create a new cache only for certain arguments/properties
}

A note on options.keys. Let's say you supply the entire req object but for caching reasons the funciton is only interested in req.params.id. Then the following would consider requests to be the same if anything but req.params.id changes.

// 0 for the first argument
cache = hamster(fn, { keys: ['0.params.id'] });

Examples

Cache an ajax request

// Will only request a post from the server the first time
var getPost = hamster(function (id, callback) {
  $.ajax({
    url: '/posts/' + id,
    success: callback
  });
}, {
  ttl: 0
});

$('.toc a').on('click', function(e) {
  e.preventDefault();
  getPost($(this).attr('data-id'), function (data) {
    renderPost(data);
  });
});

Cache a custom mongoose method

postSchema.statics.getFull = hamster(function (id, callback) {
  this.findById(id).populate('author').exec(callback);
});

// ... used in routing like normal:
app.get('/:id', function (req, res) {
  postModel.getFull(req.params.id, function (post) {
    res.render('post', post);
  });
});

See the test folder for more examples.

Custom extensions

Want to store the caches in redis or localStorage instead of in-memory? Go ahead and implement .store, .hasCache, .getCache, .addTimeout, and possibly any other methods on a cache instance. I will probably implement a neater api for this later.

Contribution

Create an issue first so I know what you're doing. Pull request to the develop branch. Test everything.

Todo

AKA implemented when/if needed.

  • A way of expiring based on some other criteria than time. Eg number of calls or some external change. Probably in the form of a .expireWhen() option.
  • A way to auto-update a cache instead of exipring. A must for very heavy work which not even one client can wait for.
  • API for using custom storage mechanisms.

License

MIT

Copyright (C) 2013 Andreas Hultgren