decorators-utils, a neat approach for utility functions in JavaScript

We will all agree that utility functions are helping us to keep a healthy code base as they are preventing us from writing the same code over and over again across our applications.

In this article I would like to introduce you to some util functions that I have created but instead of writing them as simple functions I decided to write them as decorators (If you don’t know what are decorators, I encourage you to read this article). Some of the decorators were inspired by libraries like Lodash and Underscore.

Here is the list of the available decorators with their description.

@after, @before

Sometimes you want to execute some logic before/after you run the original piece of code, these decorators will do exactly that. Probably good for debugging and monitoring.

@cancelPrevious

Imagine that you have a dashboard that after its load it requests some data to show to the user, while it’s loading the user can change the date range (or any other component) that triggers another call to the same data provider. In this scenario, we would likely to cancel the first request (cancel the promise) that was made and wait for the resolving of the second call.
This decorator does exactly that, if the decorated method (the data provider) will be invoked while the previous invocation wasn’t resolved yet, it will cancel the first one and proceed with the second.

@debounce

Delays the invocation of the decorated method until after wait have elapsed since the last time the decorated method was invoked.

@delay

Delays the invocation of the decorated method until after wait milliseconds.

@memoize

Stores in a cache the result of the invocation of the decorated method. By default the cache key would be a serialization of the invocation arguments. You can provide your own key resolver if the custom one is not good enough.
A custom cache (should implement get, set, has ,delete methods) can be provided to the decorator. This is good for 3 common cases:

  • Share the same instance of the cache between multiple methods.
  • Have a better control over the cache entries.
  • Providing different type of cache per use case, for example, you could
    provide a Map and this will serve as a local cache, but you could also provide a Redis client which will store the values in a distributed manner.

@memoizeAsync

This decorator resembles the @memoize decorator but it serves for methods that return a promise.
Promises should be handled a bit differently and some optimizations can be made. For example, let’s say that your node server receives thousands of request per second and for each request you are accessing your DB, by adding a caching layer you could reduce your response time and reduce load on the DB. But we can do better by making sure that we are not accessing the DB (when there are cache misses) if a request with the same key was already made in that period of time and wasn’t resolved yet.
The @memoizeAsync decorator will do the described above, note that rejected promises won’t be cached.

@onError

This decorator will invoke the provided function if an error will occur in the invocation of the decorated method. If the decorated method is returning a promise (and wait is set to true in the decorator configuration) the decorator will handle the rejected promise.

@readonly

When a property is decorated with the @readonly decorator it becomes un-assignable.

@refreshable

Sometimes you want to have a data which is being refreshed once in a while, the @refreshable decorator will populate the decorated property every interval with the response of the provided function.
This decorator becomes very useful when you have data which is not being changed too often and your use-case can work with not a fresh data for 100% of the time.

@throttle

Makes the decorated method to be invoked at most once per every wait milliseconds. This decorator will be useful when you want to “spread” the amount of invocation of the decorated method.

Information & Installation

You can find the utils-decorators on the following GitHub link. You can install it via npm:

npm i --save utils-decorators

The library was written in TypeScript and transpiled to es5 supporting platforms. Note that plain JavaScript (node & web apps) can use utils-decorators as well.

Summary and future plans

While creating this library I already thought of creating some more util decorators and you can find and track their progress in the issue section of the repo on GitHub.

I will be more than happy to hear more ideas for other utils decorators.
The library has many tests and is well covered. Unfortunately it doesn’t means that there are no bugs in it. If you find one please open an issue and I will address it.

I hope you will find this library useful and I will much appreciate to hear your feedback and suggestions for improvements in the comments section below.

Father, Husband & FullStack Developer