如何记忆基于承诺的功能?
直接记忆该功能是否足够?
function foo() {
return new Promise((resolve, reject) => {
doSomethingAsync({ success: resolve, fail: reject });
});
};
这样就够了吗?
var fooMemoized = memoize(foo);
注意:此问题已更新,以删除延迟反模式。
答案 0 :(得分:12)
是的,这就足够了。 Promise是简单的返回值,这是它们的巨大好处 - 与回调相比,memoisation代码会很糟糕。
如果您的诺言库确实支持某种取消,您可能只想确保备忘的承诺无法撤销。另请注意,这种形式的记忆也会记住拒绝,因此您无法通过“再次尝试”来从错误中恢复。
答案 1 :(得分:4)
对于promises,简单同步memoize不会很好,因为在大多数情况下你不希望记住错误(拒绝承诺)。
我为常见需求做了一个简单的库:https://github.com/nodeca/promise-memoize
伪代码:
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));
答案 2 :(得分:2)
请注意,您的函数具有延迟反模式,可以进一步简化:
foo.value = null;
function foo(){
if(foo.value) return foo.value;
return (foo.value = doSomethingAsync());
}
也就是说,在这种情况下,记忆很简单,你甚至不必致电.memoize
。您的原始功能也会抑制错误。
答案 3 :(得分:2)
正如@Bergi和@BenjaminGruenbaum指出的那样,这里的memoization很好,但是应该指出你的foo
函数正在做 nothing 有用并且实际上是在引入bug (参见:deferred antipattern)。
如果您只想记住doSomethingAsync
的结果,那么您可以删除中间人:
var fooMemoized = memoize(doSomethingAsync);
或者,如果您实际上过于简单并且foo()
正在将参数传递给doSomethingAsync
,那么您仍然可以将其减少到一行:
function foo() {
return doSomethingAsync(argument1, argument2, etc.);
}
var fooMemoized = memoize(foo);
或者,如果您实际上并不打算使用foo()
,则可以执行以下操作:
var fooMemoized = memoize(function () {
return doSomethingAsync(argument1, argument2, etc.);
});
答案 4 :(得分:0)
记忆和承诺并不明显。使用新的async / await语法甚至更糟糕。
为了得到像这样的工作:
memoize(async () => 42)
或
const whatsTheAnswerToLifeTheUniverseAndEverything = () => 42
memoize(whatsTheAnswerToLifeTheUniverseAndEverything)
您需要一个支持promises和异步语法的memoize函数或库。其中几个: - https://github.com/aboutlo/async-memo-ize(披露:我做了这个lib) - https://github.com/medikoo/memoizee
注意:Memoization是一种很酷的技术,但是你会以内存消耗为代价来节省CPU资源。您应该注意这些库如何大规模地解决这个问题;)