In this article I would like to show you how you could use the @ decorator, from the , in your application (both node and web) in one of the most elegant and simple ways. memoizeAsync utils-decorators library Let’s say we have the following class: SettingsProviderClient { getSettings(context): <SettingsDto> { ... } } export class Promise As you can see, the getSettings is returning a Promise of SeettingsDto. Now let’s say that we would like to have some caching which will check if a call was made in the last 10 minutes to getSettings with the same context then it would be pulled from the cache and won’t be resolved again. First step, install the utils-decorators library: npm install --save utils-decorators r Second step, apply the @ memoizeAsync decorato : { memoizeAsync } ; SettingsProviderClient { ( * * ) getSettings(context): <SettingsDto> { ... } } import from 'utils-decorators' export class @memoizeAsync 1000 60 10 // 10 minutes in ms Promise That’s all! Now you have a 10 minutes cache. Wait! there are more options In the next few paragraphs we will discuss the API and it’s more advanced configurations. @ memoizeAsync By default the decorator will put as the key of a cache entry the string which is generated by running JSON.stringify on the provided arguments to the decorated method. If you would like to change this behaviour then you will need to provide your own key resolver: Custom key resolving: ({ keyResolver: context.id.toString(), expirationTimeMs: * * }) getSettings(context): <SettingsDto> { ... } @memoizeAsync ( ) => context 1000 60 10 Promise The cache attribute is expecting to receive an object that implements the Cache interface ( ): which the JavaScriptMap object implements by default Cache<D> { : ; : D | ; : ; has: ; } interface set ( ) => key: , value: D string void get ( ) => key: string null delete ( ) => key: string void ( ) => key: string boolean In many cases you have more than one instance of your application running, in this cases you might want to have a distributed cache which all the instances of the application can share. To achieve this you need to provide your custom cache which should implement the AsynCache interface Distributed cache: AsyncCache<D> { : < >; : <D> | < >; : < >; has: < >; } interface set ( ) => key: , value: D string Promise void get ( ) => key: string Promise Promise null delete ( ) => key: string Promise void ( ) => key: string Promise boolean The AsyncCache interface resembles the Cache interface but notice that every operation is async (returning a Promise). For example, let’s say that we are using Redis (you can see a full implementation in this ) as our distributed cache: gist ({ keyResolver: context.id.toString(), expirationTimeMs: * * , cache: redisCache }) getSettings(context): <SettingsDto> { ... } @memoizeAsync ( ) => context 1000 60 10 Promise You probably noticed that both the local and the async caches are provided via the same cache attribute, so if we would like to use different caches for different environments we could achieve this with a simple condition check: Different cache types for different environments ({ keyResolver: context.id.toString(), expirationTimeMs: * * , cache: isProd() ? redisCache : Map() }) getSettings(context): <SettingsDto> { ... } @memoizeAsync ( ) => context 1000 60 10 new Promise Summery Almost every production app has a cache, and dealing with a cache might be painful and inconvenient. IMO, by using a decorator this ordeal becomes much more pleasant, elegant and clear. Previously published on Medium