From a49b1d01ead98f91b7237b3d24e482efed5746c0 Mon Sep 17 00:00:00 2001 From: tshemsedinov Date: Tue, 21 Nov 2017 04:09:56 +0200 Subject: [PATCH] Async memoize first implementation Refs: https://github.com/metarhia/metasync/issues/268 --- lib/memoize.js | 49 +++++++++++++++++++++++++++++++++++++++++++++++++ metasync.js | 3 ++- test/memoize.js | 39 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 90 insertions(+), 1 deletion(-) create mode 100644 lib/memoize.js create mode 100644 test/memoize.js diff --git a/lib/memoize.js b/lib/memoize.js new file mode 100644 index 00000000..823cac0c --- /dev/null +++ b/lib/memoize.js @@ -0,0 +1,49 @@ +'use strict'; + +const util = require('util'); + +function Memoized() { +} + +util.inherits(Memoized, Function); + +const memoize = ( + // Create memoized function + fn // function, sync or async + // Returns: function, memoized +) => { + const cache = new Map(); + + const memoized = function(...args) { + const callback = args.pop(); + const key = args[0]; + const record = cache.get(key); + if (record) { + callback(record.err, record.data); + return; + } + fn(...args, (err, data) => { + cache.set(key, { err, data }); + callback(err, data); + }); + }; + + const fields = { + cache, + timeout: 0, + limit: 0, + size: 0, + maxSize: 0 + }; + + Object.setPrototypeOf(memoized, Memoized.prototype); + return Object.assign(memoized, fields); +}; + +Memoized.prototype.clear = function() { + this.cache.clear(); +}; + +module.exports = { + memoize, +}; diff --git a/metasync.js b/metasync.js index 725e8a87..624b9050 100644 --- a/metasync.js +++ b/metasync.js @@ -9,7 +9,8 @@ const submodules = [ 'array', // Array utilities 'chain', // Process arrays sync and async array in chain 'collector', // DataCollector and KeyCollector - 'queue', // Concurrency + 'queue', // Concurrent queue + 'memoize', // Async memoization ].map(path => require('./lib/' + path)); const flow = submodules[0].flow; diff --git a/test/memoize.js b/test/memoize.js new file mode 100644 index 00000000..cc61c189 --- /dev/null +++ b/test/memoize.js @@ -0,0 +1,39 @@ +'use strict'; + +const tap = require('tap'); +const metasync = require('..'); + +tap.test('memoize', (test) => { + const storage = { + file1: Buffer.from('file1'), + file2: Buffer.from('file2'), + }; + + const getData = (file, callback) => { + process.nextTick(() => { + const result = storage[file]; + if (result) callback(null, result); + else callback(new Error('File not found')); + }); + }; + + const memoizedGetData = metasync.memoize(getData); + + memoizedGetData('file1', (err, data) => { + test.error(err); + test.strictSame(data, storage.file1); + memoizedGetData('file2', (err, data) => { + test.error(err); + test.strictSame(data, storage.file2); + memoizedGetData('file1', (err, data) => { + test.error(err); + test.strictSame(data, storage.file1); + memoizedGetData('file2', (err, data) => { + test.error(err); + test.strictSame(data, storage.file2); + test.end(); + }); + }); + }); + }); +});