Javascript-форум (https://javascript.ru/forum/)
-   Общие вопросы Javascript (https://javascript.ru/forum/misc/)
-   -   Function Cache (https://javascript.ru/forum/misc/52176-function-cache.html)

y0uix 06.12.2014 22:41

Function Cache
 
Всем привет!

Задача в том, что:

0) Создается некоторая функция, принимающая N аргументов;
1) Создается кэширующая функция, которая принимает вышеуказанную в качестве фунарга и дальше с возвращенным ей значением мы можем работать следующим образом:
- если такая функция-обертка вызывается с новым набором аргументов, то выполняется оригинальная функция;
- в противном случае, если вызов с такими аргументами уже был, то возвращается закэшированный результат, без вызова.

Вот оригинальное описание: "If you are calculating complex things or execute time-consuming API calls, you sometimes want to cache the results. In this case we want you to create a function wrapper, which takes a function and caches its results depending on the arguments, that were applied to the function."

Мой код:

function cache(func) {
  var cached_func = func,
      cached_func_data = [];
  
  return function() {
    var args_len = arguments.length,
        i,
        j;
    
    if (!cached_func_data.length) {
      return callCachedFunc(arguments);
    }
    
    for (i = 0; i < args_len; i++) {
      for (j = 0; j < cached_func_data[i].args.length; j++) {
        if (cached_func_data[i].args[i] === arguments[i]) {
          continue;
        }
        return cached_func_data[i].res;
      }
      return callCachedFunc(arguments);
    }
    
    function callCachedFunc(arguments) {
      var cache_obj = {};
      cache_obj.args = Array.prototype.slice.call(arguments);
      cache_obj.res = cached_func.apply(null, arguments);
      cached_func_data.push(cache_obj);
      return cache_obj.res;
    }
  }
}


Прошу провести ревью кода. Решение не полностью корректно, но я не могу пока что, к большому своему огорчению, найти ошибку.

Спасибо.

y0uix 06.12.2014 23:18

Вот пример использования:
var complexFunction = function(arg1, arg2) { /* complex calculation in here */ };
var cachedFunction = cache(complexFunction);

cachedFunction('foo', 'bar'); // complex function should be executed
cachedFunction('foo', 'bar'); // complex function should not be invoked again, instead the cached result should be returned
cachedFunction('foo', 'baz'); // should be executed, because the method wasn't invoked before with these arguments


Заранее благодарен за любые комментарии по делу.

nerv_ 07.12.2014 00:48

https://yadi.sk/i/er6gs7TEdCUGg

krutoy 07.12.2014 02:37

nerv_,
чушь собачья
a=Object.create({a: 1})
b=Object.create({a: 2})
fu=function(){
  var f=function(arg){return arg.a} 
  return function(){alert(JSON.stringify(arguments)); return f(arguments[0])}
}()

alert(fu(a))
alert(fu(b))

//  {"0":{}}
//  1
//  {"0":{}}
//  2

Закешировали, ага.

bes 07.12.2014 10:37

я вчера было уже хотел выложить вариант с двумя массивами, но вариант nerv_ c cache[stamp] дал понять, где настоящий скил :)

в качестве отработки при помощи FineReader-a извлёк код nerv_ (шутка :D )
function f(a, b, c) {
	return a * b + c;
};

function cacheFn(fn) {
	var cache = {};
	return function () {
		var stamp = JSON.stringify(arguments); 
		console.log(cache);
		if (!(stamp in cache)) {
			cache[stamp] = fn.apply(this, arguments);
			console.log("call: " + cache[stamp]);
		}
		console.log("cache: " + cache[stamp] + "\n\n");
		return cache[stamp];
	
	}
}

var cacheF = cacheFn(f);
cacheF(2, 2, "asdf");
cacheF(2, 2, "asdf");
cacheF(2, 3, "asdf");
cacheF(2, 3, "asdf");

Vlasenko Fedor 07.12.2014 12:35

if (!cache.hasOwnProperty(stamp)) {/*... */}

а так не лучше будет?

bes 07.12.2014 12:51

Цитата:

Сообщение от Poznakomlus (Сообщение 345234)
if (!cache.hasOwnProperty(stamp)) {/*... */}

а так не лучше будет?

лучше, потому что немного быстрее, но это из области незначительной оптимизации, а вот хранение информации в ключах объекта - это из области гениального :)

nerv_ 07.12.2014 13:49

Цитата:

Сообщение от bes
а вот хранение информации в ключах объекта - это из области гениального

стандартный прием)

Общепринятое название функции memorize (у меня на скрине опечатка, скопипастил название у lowdash), от memorization
https://lodash.com/docs#memoize

Читайте Стоян Стефанов - JavaScript. Шаблоны, там все есть

Ну, и, разумеется, такая функция принимает только примитивы + json like objects. Если очень хочется пихать объекты с циклическими ссылками, то массивы.

danik.js 07.12.2014 13:59

Цитата:

Сообщение от nerv_
Общепринятое название функции memorize

:no: http://en.wikipedia.org/wiki/Memoization

nerv_ 07.12.2014 14:12

danik.js, значит в книжке опечатка)

https://yadi.sk/i/IlMM8krQdCoLf

https://ru.wikipedia.org/wiki/%D0%9C...%D 0%B8%D1%8F

или в википедии опечатка, т.к. запоминание согласно переводчику гугла это memorization от слова memory (насколько я понимаю)
https://translate.google.ru/#en/ru/memorization


Часовой пояс GMT +3, время: 20:10.