2015-02-27 18 views
5

Jak mogę zapamiętać funkcję opartą na obietnicy?Memoization of promise-based function

Czy wystarczy zwykła zapamiętywanie funkcji?

function foo() { 
    return new Promise((resolve, reject) => { 
     doSomethingAsync({ success: resolve, fail: reject }); 
    }); 
}; 

Czy to wystarczy?

var fooMemoized = memoize(foo); 

Uwaga: kwestia ta została zaktualizowana, aby usunąć odroczony anty-wzór.

+1

Tak, to powinno działać. Po raz pierwszy fooMemoized nazywa się foo() będzie działać i zwróci obietnicę. Memoize następnie "cache", że obietnica. Każde wezwanie do fooMemoized zwróci tę samą obietnicę, która, jeśli zostanie oznaczona jako rozwiązana, zostanie uruchomiona natychmiast. – startswithaj

+4

Zwróć uwagę na swój anty-wzór w implementacji 'foo()'. Całe jego ciało może być po prostu 'return doSomethingAsync();' – jfriend00

+0

@ jfriend00: s/could/should/:-) Ta forma [odroczonego antipattern] (http://stackoverflow.com/q/23803743/1048572) nie działa przekazywać błędy. – Bergi

Odpowiedz

10

Tak, to wystarczy. Obietnice są prostymi wartościami zwracanymi, co jest ich wielką zaletą - w przeciwieństwie do wywołań zwrotnych, gdzie kod zapamiętania byłby okropny.

Możesz tylko upewnić się, że pamiętana obietnica jest nieusuwalna, jeśli twoja biblioteka obietnic wspiera jakieś anulowanie. Zauważ też, że ta forma zapamiętania pamięta również odrzucenia, więc nie można odzyskać od błędów przez "próbowanie ponownie".

2

pamiętać, że funkcja ma odroczony anty wzór i można uprościć dalej:

foo.value = null; 
function foo(){ 
    if(foo.value) return foo.value; 
    return (foo.value = doSomethingAsync()); 
} 

Oznacza to, memoization jest tak prosta w tym przypadku nie trzeba nawet dzwonić .memoize. Również oryginalna funkcja pomijała błędy.

+0

Czy to jest próba komentowania odpowiedzi @azaviruha? Nie wiesz, co masz na myśli. – Bergi

+0

Przepraszam, nie spałem od jednego dnia. Już poprawiłem twoją odpowiedź, ale zauważyłem, że OP może wbudować to w funkcję –

+1

Hm, myślę, że całkiem dobrze jest robić notatki za pomocą funkcji wyższego rzędu i nie zagracać logiki 'foo' (tak prostej jak to tylko możliwe) z nią . – Bergi

2

Jak @Bergi i @BenjaminGruenbaum podkreśliło, tak memoization jest w porządku tutaj, ale należy podkreślić, że funkcja foo robi nic użyteczne i rzeczywiście wprowadza błędy (patrz: odroczony antywzorzec projektowy).

Jeśli chcesz to do memoize wynik doSomethingAsync, to można wyciąć środkowo-Man:

var fooMemoized = memoize(doSomethingAsync); 

Lub jeśli rzeczywiście upraszczając i foo() przechodzi argumentów doSomethingAsync, wówczas można nadal je zmniejszyć do jednej linii:

function foo() { 
    return doSomethingAsync(argument1, argument2, etc.); 
} 
var fooMemoized = memoize(foo); 

Lub jeśli w rzeczywistości nie planujesz używać foo(), można zrobić:

var fooMemoized = memoize(function() { 
    return doSomethingAsync(argument1, argument2, etc.); 
}); 
3

Za obietnice zwykła synchronizacja na pamięć nie będzie dobra, ponieważ w większości przypadków nie będzie chciało się pamiętać błędów (odrzuconych obietnic).

Zrobiłem prosty biblioteki dla wspólnych potrzeb: https://github.com/nodeca/promise-memoize

  1. To funkcja Obietnica oparte memoize, z wyjątkiem błędów domyślnie
  2. Można ustawić czas wygaśnięcia na skutek
  3. Jeśli trzeba, można pamiętaj (i ustaw czas wygaśnięcia) również na błędy.
  4. Dane mogą zostać wstępnie zapisane przed wygaśnięciem, aby nigdy nie pozostawiać pamięci podręcznej w stanie zimnym.

Pseudo kod:

let db = require('mongoose').createConnection('mongodb://localhost/forum'); 

function lastPosts(limit) { 
    return db.model('Post').find() 
    .limit(limit).orderBy('-_id').lean(true).exec(); // <- Promise (thenable) 
} 

let cachedLastPosts = require('promise-memoize')(lastPosts, { maxAge: 60000 }); 

// Later... 
cachedLastPosts(10).then(posts => console.log(posts)); 
0

memoization i obietnice nie są oczywiste. Najgorsze nawet z nową składnią async/await.

w celu uzyskania jak somewhint że praca:

memoize(async() => 42) 

lub

const whatsTheAnswerToLifeTheUniverseAndEverything =() => 42 
memoize(whatsTheAnswerToLifeTheUniverseAndEverything) 

Trzeba funkcję memoize lub biblioteki, która obsługuje obietnice i składni asynchronicznej. Kilka z nich: - https://github.com/aboutlo/async-memo-ize (Disclosure: Zrobiłem to lib) - https://github.com/medikoo/memoizee

Wskazówka: memoization jest fajna technika jednak zaoszczędzić zasoby procesora kosztem zużyciu pamięci. Powinieneś zadbać o to, aby te biblioteki podchodziły do ​​tej kwestii na dużą skalę;)