Как исправить эту кешированную функцию - PullRequest
0 голосов
/ 01 января 2019

Я пытаюсь создать кэшированную функцию, но даже после сохранения кэшированного значения в переменной, оно всегда вызывает условие не кэширования результата.

В моем коде я сохранил результат впеременная cachedValue.Функция, которую я должен кэшировать ('foo'), должна вызываться только в том случае, если передано новое значение в аргументе ('arg')

function cacheFunction(foo) {
  const cachedValue = [];
  return (arg) => {
    if (cachedValue[arg]) {
      return cachedValue[arg];
    }
    cachedValue[arg] = foo(arg);
    return cachedValue[arg];
  };
}

export { cacheFunction };

Тестовый код

import { cacheFunction } from './cacheFunction';

describe('cacheFunction', () => {
  it('should cache function results and not rerun the original callback if the same arguments are presented', () => {
    const foo = jest.fn();
    const myCachedFunction = cacheFunction(foo);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(true);
    myCachedFunction(10);
    myCachedFunction(10);
    myCachedFunction(10);
    myCachedFunction(10);
    myCachedFunction(10);
    expect(foo).toHaveBeenCalledTimes(2);
// It is called 10 times
  });
});

Ответы [ 2 ]

0 голосов
/ 01 января 2019

Ваша ложная функция неверна.jest.fn без аргументов просто предоставляет фиктивную функцию, которая возвращает undefined.Вам нужен тот, который возвращает что-то на основе аргумента, который он получает.Возможно:

const foo = jest.fn(x => x);

Тогда , как я сказал в комментарии , это ненадежно:

if (cachedValue[arg]) {

Что если foo вернет 0?Или ""?Или null?Или undefined?(Как на самом деле ваша фиктивная функция.)

Вместо этого используйте

if (Object.prototype.hasOwnProperty.call(cachedValue, arg)) {

Но, как сказал @NinaScholz: это работает, только если аргумент arg может быть разумно приведен к строке без потериинформация / вызывающая ложные совпадения.Карта была бы лучшим выбором, и использование WeakMap, когда arg является объектом, было бы еще лучше.

Для чего стоит:

function cacheFunction(foo) {
  const cachedValuesByPrimitive = new Map();
  const cachedValuesByObject = new WeakMap();
  return (arg) => {
    const cache = typeof arg === "object" && arg !== null
        ? cachedValuesByObject
        : cachedValuesByPrimitive;
    if (cache.has(arg)) {
      return cache.get(arg);
    }
    const result = foo(arg);
    cache.set(arg, result);
    return result;
  };
}

export { cacheFunction };

Live Пример:

function cacheFunction(foo) {
  const cachedValuesByPrimitive = new Map();
  const cachedValuesByObject = new WeakMap();
  return (arg) => {
    const cache = typeof arg === "object" && arg !== null
        ? cachedValuesByObject
        : cachedValuesByPrimitive;
    if (cache.has(arg)) {
      return cache.get(arg);
    }
    const result = foo(arg);
    cache.set(arg, result);
    return result;
  };
}

function foo(x) {
  console.log("foo called for", x);
  return x;
}

const cachingFoo = cacheFunction(foo);

cachingFoo(true);
cachingFoo(true);
cachingFoo(true);
cachingFoo(true);
cachingFoo(10);
cachingFoo(10);
cachingFoo(10);
cachingFoo(10);
const obj1 = {a: 1};
cachingFoo(obj1);
cachingFoo(obj1);
const obj2 = {a: 2};
cachingFoo(obj2);
cachingFoo(obj2);
cachingFoo(obj2);
0 голосов
/ 01 января 2019

Просто замените проверку if:

if (cachedValue[arg]) {
   return cachedValue[arg];
}

на:

if (cachedValue.hasOwnProperty(arg)) {
   return cachedValue[arg];
}

, поскольку каждый из этих элементов хранится как undefined, поэтому при первой проверке if (cachedValue[arg]) возвращает undefined, что считается false в Javascript

Я думаю, что было бы лучше, если бы вы использовали объект вместо массива для этой цели, поэтому замените

const cachedValue = [];

будет:

const cachedValue = {};

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...