Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I implement memoize method on an async function in JavaScript?

I have been trying to write the implementation of the memoize function in JavaScript. I was asked this in an interview question and haven't been able to put it out of my mind since. I would really appreciate some help with this.

Given a function in which we are making an API call -

function getSomeData(foo, callback) {
  var uri = 'http://localhost?foo=' + foo ;
  someAPIUri(uri, function onResponse(error, response, body) {
    callback(error, body);
  });
}

Instead of using an API, using setTimeout for async functionality -

function getSomeData(foo, callback) {
  setTimeout(()=> {
    console.log('async request');
    callback(2 * foo);
  }, 1000);
}

If we make a call like below twice, that means two async calls made, so we need to create a memoize function which caches the response for some input and respond with that in any subsequent call.

getSomeData(1, (response) => {
  console.log('getSomeData', response);
})

I wrote this function -

function memoize(fn) {
  const cache = {};

  return async function() {
    const args = JSON.stringify(arguments);

    console.log('arguments passed to memoize fn: ', args);
    console.log('cache data: ', cache[args]);

    cache[args] = cache[args] || fn.apply(undefined, arguments);
    return cache[args]
  }
}

const memoizedGetSomeData = memoize(getSomeData);

const callback_fn = (response) => {
  console.log('callback response: ', response);
}

memoizedGetSomeData(1, callback_fn);

memoizedGetSomeData(1, callback_fn);

This is not working as the async call is getting made for each memoizedGetSomeData call.

I would really appreciate some input to get it working and improving my understanding.

This is a codepen of the code - link

The console log:

"arguments passed to memoize fn: " "{'0':1}"
"cache data: " undefined
"arguments passed to memoize fn: " "{'0':1}"
"cache data: " undefined
"async request"
"callback response: " 2
"async request"
"callback response: " 2
like image 267
Winter Avatar asked Nov 07 '22 01:11

Winter


1 Answers

The only real issue (from what I see) is that getSomeData is a poor mock of async functionality, as it doesn't return a promise.

function getSomeData(foo, callback) {
  return new Promise((resolve, reject) => {
      setTimeout(()=> {
          console.log('async request');
          resolve(callback(2 * foo));
      }, 1000);
  });
}

function memoize(fn) {
  const cache = {};
  return async function() {
    const args = JSON.stringify(arguments);

    console.log('arguments passed to memoize fn: ', args);
    console.log('cache data: ', cache);

    cache[args] = cache[args] || fn.apply(undefined, arguments);
    return cache[args]
  }
}

const memoizedGetSomeData = memoize(getSomeData);

const callback_fn = (response) => {
  console.log('callback response: ', response);
}

memoizedGetSomeData(1, callback_fn);
memoizedGetSomeData(1, callback_fn);
like image 189
dave Avatar answered Nov 12 '22 13:11

dave