【问题标题】:How can I implement memoize method on an async function in JavaScript?如何在 JavaScript 中的异步函数上实现 memoize 方法?
【发布时间】:2021-08-20 01:32:51
【问题描述】:

我一直在尝试用 JavaScript 编写 memoize 函数的实现。我在一个面试问题中被问到这个问题,从那以后我一直无法忘记它。我非常感谢您对此提供帮助。

给定一个我们正在调用 API 的函数 -

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

不使用 API,而是使用 setTimeout 来实现异步功能 -

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

如果我们像下面这样进行两次调用,这意味着进行了两次异步调用,因此我们需要创建一个 memoize 函数来缓存某些输入的响应并在任何后续调用中进行响应。

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

这个函数是我写的-

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);

这不起作用,因为每个 memoizedGetSomeData 调用都会进行异步调用。

我非常感谢您提供一些意见,以使其发挥作用并提高我的理解力。

这是代码的codepen - link

控制台日志:

"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

【问题讨论】:

  • 使用返回 promise 的异步函数,沼泽标准 memoize 可以工作:-)

标签: javascript implementation memoization


【解决方案1】:

感谢@Bergi 和@dave 的cmets。我了解我的代码存在的问题以及 memoize 函数应该如何像异步函数一样工作。

这是在异步函数上基本实现 Memoize 的最终代码 -

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);
    cache[args] = cache[args] || fn.apply(undefined, arguments);
    return cache[args]
  }
}

const memoizedGetSomeData = memoize(getSomeData);

const callback_fn = (response) => {
  return response;
}

// this should make async call
memoizedGetSomeData(1, callback_fn).then(response => console.log('response from async call: ', response));

// this should return response from the cache
memoizedGetSomeData(1, callback_fn).then(response => console.log('cached response: ', response));

// this should make async call (different argument)
memoizedGetSomeData(4, callback_fn).then(response => console.log('response from async call: ', response));

日志:

"async request"
"response from async call: " 2
"cached response: " 2
"async request"
"response from async call: " 8

我也更新了 Codepen 代码。

【讨论】:

    【解决方案2】:

    唯一真正的问题(据我所见)是getSomeData 是对异步功能的糟糕模拟,因为它不返回承诺。

    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);

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-08-20
      • 2018-06-14
      • 2020-06-19
      • 2013-08-25
      • 2015-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多