Кэширование и предварительная выборка обещаний с истекающим сроком действия в Javascript

Промисы — это мой предпочтительный способ управления асинхронным кодом в Javascript. Memoize (memoizee на npm) — это библиотека Javascript для простого кэширования и предварительной выборки результатов функций.

В идеале я хочу объединить лучшее из обоих и иметь возможность «истекать» обещание и предварительно извлекать новый результат обещания (когда кеш затронут и близок к истечению). Memoize может это сделать, но он не был создан с учетом промисов.

(Я понимаю, что промисы имеют встроенный «вечный кеш», как и их природа, но навсегда слишком долго для моего приложения)

На данный момент моя лучшая попытка сделать это выглядит следующим образом (пример node.js с использованием bluebird, memoize и подчеркивание):

var memoize = require('memoizee')
  , Promise = require('bluebird')
  , _ = require('underscore')
  ;

// returns a memoized Promise-generating function
function memoizePromiser(funcReturningPromise, options) {
    var opts = _.defaults(options || {}, {async: true});

    return Promise.promisify(memoize(function(){
        var args = _.initial(arguments);
        var cb = _.last(arguments);
        funcReturningPromise.apply(this, args).nodeify(cb);
    }, opts));
};

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

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

Это лучший подход к тому, что я пытаюсь сделать? Есть ли другая библиотека, такая как memoize, разработанная специально для промисов? Есть ли более простое решение, которое я пропустил?

Любое руководство будет оценено.


person Mikuso    schedule 21.10.2014    source источник
comment
Не могли бы вы объяснить, что именно не так только с memoize(funcReturningPromise, options)? Может быть, я не понимаю, что существует особое поведение в отношении истечения срока действия и т. Д. С асинхронными функциями или около того, не так ли?   -  person Bergi    schedule 21.10.2014
comment
Эврика! Спасибо, что указали на это. Я был захвачен идеей, что, поскольку я имел дело с асинхронным кодом, мне пришлось использовать асинхронную функциональность memoize (включая беспорядочные обратные вызовы, подобные узлам), но я этого не делаю; Обещание возвращается синхронно.   -  person Mikuso    schedule 22.10.2014
comment
Сделаю ответ :-)   -  person Bergi    schedule 22.10.2014


Ответы (2)


Эта функция позволит мне запомнить асинхронную функцию (с обратными вызовами, подобными узлам), возвращающую обещание. Тем не менее, этот подход кажется мне грязным и чрезмерно разработанным.

Да — у вас уже есть функция, возвращающая промис, нет причин возвращаться к нодбэкам.

Есть ли более простое решение, которое я пропустил?

Функция, возвращающая обещание, — это просто функция, возвращающая какое-то значение — значение, которое может кэшироваться функцией memoize. Просто сделайте

memoize(funcReturningPromise, options)
person Bergi    schedule 22.10.2014
comment
Что произойдет, если funcReturningPromise не удастся? Вы кэшируете сбой? - person Phil C; 30.03.2015
comment
@PhilC: Да, в этом случае отклоненное обещание будет кэшировано. Однако я думаю, что это ожидаемо, цель мемоизации - предотвратить множественные запросы. Если вы этого не хотите, вы все равно можете перехватывать отказы или очищать кеш мемоизации. - person Bergi; 30.03.2015
comment
Понятно. Я смотрел на него только для хранения хороших значений, поэтому, как вы говорите, мне нужно ловить отклонения и следить за тем, чтобы они не попадали в кеш-спасибо. - person Phil C; 01.04.2015
comment
@PhilC: обратите внимание, что для правильной работы обещание должно попасть в кеш прежде, когда вы узнаете, что оно будет отклонено. Таким образом, без решения, которое предотвращает отклонение промисов (например, повтор), вы захотите удалить промис из кеша, в котором он уже находится, при отклонении. - person Bergi; 01.04.2015

Вы правильно понимаете промисы - промис - это прокси для значения - однажды установленное, оно никогда не изменится.

Единственный способ обойти это — не возвращать каждый раз одно и то же обещание — вам придется каждый раз возвращать другое обещание (как в вашем примере). Самым простым решением было бы использовать memoize с функциями возврата промисов (и это кэшировало бы promise для значения).

Если у нас есть function foo(){, который возвращает обещание. Совершенно нормально просто memoize использовать эту функцию, а затем использовать все инструменты, предоставляемые библиотекой.

Примечание: promisify является дорогостоящим и производит очень быструю функцию - вы действительно не хотите вызывать ее во время выполнения. Вы можете просто вернуть new Promise в свой код.

person Benjamin Gruenbaum    schedule 21.10.2014