基于承诺的函数的记忆
Memoization of promise-based function
如何记忆基于 promise 的函数?
函数的直接记忆是否足够?
function foo() {
return new Promise((resolve, reject) => {
doSomethingAsync({ success: resolve, fail: reject });
});
};
这就够了吗?
var fooMemoized = memoize(foo);
注意:此问题已更新以删除延迟的反模式。
是的,这就足够了。 Promises 是简单的 return 值,这是它们的巨大好处 - 与回调相比,记忆代码会很糟糕。
如果您的 promise 库确实支持某种取消,您可能只想确保 memoized promise 是不可取消的。另请注意,这种形式的记忆也会记住拒绝,因此您无法通过 "trying again".
从错误中恢复
请注意,您的函数具有延迟反模式,可以进一步简化:
foo.value = null;
function foo(){
if(foo.value) return foo.value;
return (foo.value = doSomethingAsync());
}
也就是说,在这种情况下,记忆非常简单,您甚至不必调用 .memoize
。您的原始功能也抑制了错误。
正如@Bergi 和@BenjaminGruenbaum 所指出的,是的,记忆在这里很好,但应该指出你的 foo
功能什么都没有有用并且实际上引入了错误(请参阅:延迟反模式)。
如果你只想记住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.);
});
对于 promises 简单的同步记忆不是很好,因为在大多数情况下你不希望记住错误(拒绝的 promises)。
我做了一个简单的库来满足常见的需求:https://github.com/nodeca/promise-memoize
- 它会记忆基于 Promise 的函数,默认错误除外
- 您可以为结果设置过期时间
- 如果需要,您也可以记住(并设置过期时间)错误。
- 可以在过期之前预取数据,永远不会让缓存处于冷状态。
伪代码:
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));
记忆和承诺并不明显。新的 async / await 语法更糟糕。
为了获得像这样的提示:
memoize(async () => 42)
或
const whatsTheAnswerToLifeTheUniverseAndEverything = () => 42
memoize(whatsTheAnswerToLifeTheUniverseAndEverything)
您需要一个支持 promises 和异步语法的 memoize 函数或库。其中几个:
- https://github.com/aboutlo/async-memo-ize(披露:我做了这个库)
- https://github.com/medikoo/memoizee
注意:记忆化是一项很酷的技术,但是您可以以内存消耗为代价节省 CPU 资源。您应该注意这些库是如何大规模处理这个问题的;)
如何记忆基于 promise 的函数?
函数的直接记忆是否足够?
function foo() {
return new Promise((resolve, reject) => {
doSomethingAsync({ success: resolve, fail: reject });
});
};
这就够了吗?
var fooMemoized = memoize(foo);
注意:此问题已更新以删除延迟的反模式。
是的,这就足够了。 Promises 是简单的 return 值,这是它们的巨大好处 - 与回调相比,记忆代码会很糟糕。
如果您的 promise 库确实支持某种取消,您可能只想确保 memoized promise 是不可取消的。另请注意,这种形式的记忆也会记住拒绝,因此您无法通过 "trying again".
从错误中恢复请注意,您的函数具有延迟反模式,可以进一步简化:
foo.value = null;
function foo(){
if(foo.value) return foo.value;
return (foo.value = doSomethingAsync());
}
也就是说,在这种情况下,记忆非常简单,您甚至不必调用 .memoize
。您的原始功能也抑制了错误。
正如@Bergi 和@BenjaminGruenbaum 所指出的,是的,记忆在这里很好,但应该指出你的 foo
功能什么都没有有用并且实际上引入了错误(请参阅:延迟反模式)。
如果你只想记住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.);
});
对于 promises 简单的同步记忆不是很好,因为在大多数情况下你不希望记住错误(拒绝的 promises)。
我做了一个简单的库来满足常见的需求:https://github.com/nodeca/promise-memoize
- 它会记忆基于 Promise 的函数,默认错误除外
- 您可以为结果设置过期时间
- 如果需要,您也可以记住(并设置过期时间)错误。
- 可以在过期之前预取数据,永远不会让缓存处于冷状态。
伪代码:
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));
记忆和承诺并不明显。新的 async / await 语法更糟糕。
为了获得像这样的提示:
memoize(async () => 42)
或
const whatsTheAnswerToLifeTheUniverseAndEverything = () => 42
memoize(whatsTheAnswerToLifeTheUniverseAndEverything)
您需要一个支持 promises 和异步语法的 memoize 函数或库。其中几个: - https://github.com/aboutlo/async-memo-ize(披露:我做了这个库) - https://github.com/medikoo/memoizee
注意:记忆化是一项很酷的技术,但是您可以以内存消耗为代价节省 CPU 资源。您应该注意这些库是如何大规模处理这个问题的;)