在这个答案中,承诺链是递归构建的。
略为简化,我们有:
function foo() {
function doo() {
// always return a promise
if (/* more to do */) {
return doSomethingAsync().then(doo);
} else {
return Promise.resolve();
}
}
return doo(); // returns a promise
}这大概会产生一个调用堆栈和一个承诺链--即“深”和“宽”。
我预计内存峰值会比执行递归或单独构建承诺链更大。
发布于 2015-04-28 17:27:46
免责声明:过早优化是不好的,找出性能差异的真正方法是对代码进行基准测试,您不应该担心这一点(我只需要做一次,我已经为至少100个项目使用了承诺)。
是这样吗?
是的,,承诺必须“记住”它们遵循的内容,如果您对10000的承诺执行此操作,您将有一个10000长的承诺链,如果不这样做,您就不会(例如,使用递归)--对于任何排队流控制都是这样。
如果你必须跟踪10000件额外的东西(操作),那么你需要为它保留内存,这需要时间,如果这个数字是一百万,它可能是不可行的。各图书馆的情况各不相同。
有没有人考虑过以这种方式构建链的记忆问题?
当然,这是一个很大的问题,也是在库中使用像Promise.each这样的东西的用例,比如蓝鸟在then上的链接。
为了避免这种风格,我个人在代码中使用了一个快速应用程序,它只遍历VM中的所有文件--但在绝大多数情况下,这是一个没有问题的问题。
记忆消耗在承诺库之间会有所不同吗?
是的,很大。例如,如果检测到承诺操作已经是异步的(例如,如果它以Promise.delay启动),并且只会同步执行(因为异步保证已经被保留),它就不会分配额外的队列。
这意味着,我在回答第一个问题时所声称的并不总是正确的(但在常规用例中是正确的):除非提供内部支持,否则本机承诺永远无法做到这一点。
再说一遍,这并不令人惊讶,因为承诺库之间的差别是数量级的。
发布于 2016-04-14 06:34:35
我刚刚发现了一种可能有助于解决问题的方法:不要在最后一个then中执行递归,而是在最后一个catch中执行递归,因为catch已经超出了解决链。使用您的例子,应该是这样的:
function foo() {
function doo() {
// always return a promise
if (/* more to do */) {
return doSomethingAsync().then(function(){
throw "next";
}).catch(function(err) {
if (err == "next") doo();
})
} else {
return Promise.resolve();
}
}
return doo(); // returns a promise
}发布于 2016-07-12 14:34:25
作为对现有答案的补充,我想说明这个表达式,它是这样一个异步递归的结果。为了简单起见,我使用一个简单的函数来计算给定基和指数的幂。递归和基本情况等价于OP的示例:
const powerp = (base, exp) => exp === 0
? Promise.resolve(1)
: new Promise(res => setTimeout(res, 0, exp)).then(
exp => power(base, exp - 1).then(x => x * base)
);
powerp(2, 8); // Promise {...[[PromiseValue]]: 256}在某些替代步骤的帮助下,可以替换递归部分。请注意,可以在浏览器中计算此表达式:
// apply powerp with 2 and 8 and substitute the recursive case:
8 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 8)).then(
res => 7 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 7)).then(
res => 6 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 6)).then(
res => 5 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 5)).then(
res => 4 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 4)).then(
res => 3 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 3)).then(
res => 2 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 2)).then(
res => 1 === 0 ? Promise.resolve(1) : new Promise(res => setTimeout(res, 0, 1)).then(
res => Promise.resolve(1)
).then(x => x * 2)
).then(x => x * 2)
).then(x => x * 2)
).then(x => x * 2)
).then(x => x * 2)
).then(x => x * 2)
).then(x => x * 2)
).then(x => x * 2); // Promise {...[[PromiseValue]]: 256}口译:
new Promise(res => setTimeout(res, 0, 8)),执行器将被立即调用,并执行非阻塞计算(用setTimeout模拟)。然后返回一个未确定的Promise。这与OP示例中的doSomethingAsync()相当。Promise通过.then(...与此解析回调相关联。注意:这个回调的主体被powerp的主体所取代。then处理程序结构,直到达到递归的基本情况。基本大小写返回用Promise解析的1。then处理程序结构通过相应地调用关联的回调来“解除”。为什么生成的结构是嵌套的而不是链式的?因为then处理程序中的递归大小写阻止它们返回一个值,直到达到基本大小写为止。
如果没有堆栈,这怎么能工作呢?关联的回调形成一个“链”,它连接主事件循环的连续微任务。
https://stackoverflow.com/questions/29925948
复制相似问题