我正在尝试创建一个缓存的函数,但是即使将缓存的值存储在变量中之后,它始终会触发未缓存结果的情况。
在我的代码中,我将结果存储在变量cachedValue中。 只有在参数('arg')中传递了新值时,才应调用我应该缓存的函数('foo')
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
});
});
答案 0 :(得分:3)
您的模拟功能是错误的。 jest.fn
(不带参数)仅提供返回undefined
的模拟函数。您需要一个根据接收到的参数返回某些内容的对象。也许:
const foo = jest.fn(x => x);
然后,as I said in a comment这是不可靠的:
if (cachedValue[arg]) {
如果foo
返回0
怎么办?还是""
?还是null
?还是undefined
? (实际上,您的模拟函数确实可以。)
相反,使用
if (Object.prototype.hasOwnProperty.call(cachedValue, arg)) {
但是正如@NinaScholz所说:只有在arg可以合理地强制转换为字符串而不会丢失信息/导致错误匹配的情况下,它才有效。地图将是更好的选择,并且在arg
是对象的情况下使用WeakMap会更好。
对于它的价值:
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 };
实时示例:
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);
答案 1 :(得分:0)
只需替换if
语句检查:
if (cachedValue[arg]) {
return cachedValue[arg];
}
成为:
if (cachedValue.hasOwnProperty(arg)) {
return cachedValue[arg];
}
因为每个元素都存储为undefined
,所以第一个检查if (cachedValue[arg])
返回undefined
,在Javascript中将其视为false
我认为如果为此目的使用对象而不是数组也更好,所以替换
const cachedValue = [];
成为:
const cachedValue = {};