Memoization of promise-based function

可紊 提交于 2019-12-17 14:44:24

问题


How can I memoize a promise-based function?

Would straightforward memoization of the function suffice?

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

Would this suffice?

var fooMemoized = memoize(foo);

Note: this question has been updated to remove the deferred anti-pattern.


回答1:


Yes, that will suffice. Promises are simple return values, which is their great benefit - in contrast to callbacks, where memoisation code would be horrible.

You only might want to make sure that the memoized promise is uncancellable, if your promise library does support some kind of cancellation. Also notice that this form of memoisation remembers rejections as well, so you can't recover from errors by "trying again".




回答2:


For promises simple sync memoize will not be good, because in most of cases you will not wish to memoize errors (rejected promises).

I did a simple library for common needs: https://github.com/nodeca/promise-memoize

  1. It memoize Promise-based function, except errors by default
  2. You can set expiration time for result
  3. If you need, you can remember (and set expiration time) for errors too.
  4. Data can be prefetched prior to expire, to never leave cache in cold state.

Pseudo code:

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));



回答3:


Note that your function has the deferred anti pattern and can be simplified further:

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

That is, memoization is so simple in this case you don't even have to call .memoize. Also your original function suppressed errors.




回答4:


As @Bergi, and @BenjaminGruenbaum have pointed out, yes memoization is fine here, but it should be pointed out that your foo function is doing nothing useful and is actually introducing bugs (see: deferred antipattern).

If all you want is to memoize the result of doSomethingAsync, then you can cut out the middle-man:

var fooMemoized = memoize(doSomethingAsync);

Or if you were actually oversimplifying and foo() is passing arguments to doSomethingAsync, then you can still reduce it to one line:

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

Or if you don't actually plan to use foo(), you can do:

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



回答5:


Memoization and promises aren't obvious. Even worst with the new async / await syntax.

in order to get somewhint like that working:

memoize(async () => 42) 

or

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

You need a memoize function or library which supports promises and async syntax. A couple of them: - https://github.com/aboutlo/async-memo-ize (Disclosure: I did this lib) - https://github.com/medikoo/memoizee

Notice: Memoization is a cool technique however you save CPU resources at the cost of a memory consumption. You should take care how those libraries approach this issue at scale ;)



来源:https://stackoverflow.com/questions/28763057/memoization-of-promise-based-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!