Кеширане и предварително извличане на изтичащи обещания в Javascript

Обещанията са моят предпочитан начин за управление на моя асинхронен код в Javascript. Memoize (memoizee на npm) е Javascript библиотека за лесно кеширане и предварително извличане на резултати от функции.

В идеалния случай искам да комбинирам най-доброто от двете и да имам възможността да "изтеча" Promise и предварително да извлека нов резултат от Promise (когато кешът е докоснат и е близо до изтичане). Memoize може да направи това, но не е създаден с предвид Promises.

(Разбирам, че Promises имат вграден "forever-cache", както е в природата им, но forever е твърде дълго за моето приложение)

Най-добрият ми опит да направя това досега е както следва (пример на 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)


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

Да - вече имате функция, която връща обещание, няма причина да се връщате към nodebacks.

Има ли по-просто решение, което съм пропуснал?

Функция, която връща обещание, е просто функция, която връща някаква стойност - стойност, която може да бъде кеширана от функцията 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 с функции, връщащи обещание (и това ще кешира обещанието за стойността).

Ако имаме function foo(){, който връща обещание. Напълно добре е само memoize да функционира само и след това да използвате всички инструменти, предоставени от библиотеката.

Забележка: promisify е скъп и произвежда много бърза функция - наистина не искате да я извиквате по време на изпълнение. Можете просто да върнете new Promise във вашия код.

person Benjamin Gruenbaum    schedule 21.10.2014