javascript – 使用递归承诺阻止内存泄漏
作者:互联网
如何使用Q library创建JavaScript Promises的递归链?以下代码无法在Chrome中完成:
<html>
<script src="q.js" type="text/javascript"></script>
<script type="text/javascript">
//Don't keep track of a promises stack for debugging
//Reduces memory usage when recursing promises
Q.longStackJumpLimit = 0;
function do_stuff(count) {
if (count==1000000) {
return;
}
if (count%10000 == 0){
console.log( count );
}
return Q.delay(1).then(function() {
return do_stuff(count+1);
});
}
do_stuff(0)
.then(function() {
console.log("Done");
});
</script>
</html>
解决方法:
这不会堆栈溢出,因为promises会破坏堆栈,但它会泄漏内存.如果在node.js中运行相同的代码,则会出现如下错误:
FATAL ERROR: CALL_AND_RETRY_2 Allocation failed - process out of memory
这里发生的事情是,正在创建一个非常长的嵌套承诺链,每个承诺等待下一个.你需要做的是找到一种方法来压扁该链,以便只返回一个顶级承诺,等待目前代表一些实际工作的最内在的承诺.
打破链条
最简单的解决方案是在顶层构建一个新的promise并使用它来打破递归:
var Promise = require('promise');
function delay(timeout) {
return new Promise(function (resolve) {
setTimeout(resolve, timeout);
});
}
function do_stuff(count) {
return new Promise(function (resolve, reject) {
function doStuffRecursion(count) {
if (count==1000000) {
return resolve();
}
if (count%10000 == 0){
console.log( count );
}
delay(1).then(function() {
doStuffRecursion(count+1);
}).done(null, reject);
}
doStuffRecursion(count);
});
}
do_stuff(0).then(function() {
console.log("Done");
});
虽然这个解决方案有点不优雅,但您可以确定它可以在所有承诺实现中使用.
那么/ promise现在支持尾递归
一些承诺实现(例如来自npm的promise,您可以从https://www.promisejs.org/下载为独立库)正确检测到这种情况并将承诺链折叠成单个承诺.如果您不保留对顶级函数返回的承诺的引用(即,立即调用它,请不要保留它).
好:
var Promise = require('promise');
function delay(timeout) {
return new Promise(function (resolve) {
setTimeout(resolve, timeout);
});
}
function do_stuff(count) {
if (count==1000000) {
return;
}
if (count%10000 == 0){
console.log( count );
}
return delay(1).then(function() {
return do_stuff(count+1);
});
}
do_stuff(0).then(function() {
console.log("Done");
});
坏:
var Promise = require('promise');
function delay(timeout) {
return new Promise(function (resolve) {
setTimeout(resolve, timeout);
});
}
function do_stuff(count) {
if (count==1000000) {
return;
}
if (count%10000 == 0){
console.log( count );
}
return delay(1).then(function() {
return do_stuff(count+1);
});
}
var thisReferenceWillPreventGarbageCollection = do_stuff(0);
thisReferenceWillPreventGarbageCollection.then(function() {
console.log("Done");
});
不幸的是,没有任何内置的promise实现具有这种优化,并且没有任何计划实现它.
标签:q,javascript,recursion,promise,memory-leaks 来源: https://codeday.me/bug/20191005/1856766.html