以下模式调用返回承诺的递归 JavaScript 函数有什么区别? [英] What is the difference in following pattern to call recursive JavaScript function which returns a promise?
问题描述
在具有 100000 条记录的以下代码中,recursiveFnReturnsPromiseV1 执行良好,而 recursiveFnReturnsPromiseV2 因堆栈外异常而失败.两者之间的唯一区别是 promise 的递归方式.在 v1 中,递归位于第一个 promise 的then"内,而在 v2 中,递归位于原始 promise 本身内.有什么区别?
In following code with 100000 records recursiveFnReturnsPromiseV1 executes fine while recursiveFnReturnsPromiseV2 fails with out of stack exception. The only difference between two is the way promises are being recursed. In the v1, the recursion is within a "then" of the first promise while in v2, the recursion is within the original promise itself. What's the difference?
let aValues = Array(100000);
recursiveFnReturnsPromiseV1(aValues, 0).then(function() {
let p = document.createElement('div');
p.innerText = 'recursiveFnReturnsPromiseV1 finished';
document.getElementById('v1').appendChild(p);
}, function() {
let p = document.createElement('div');
p.innerText = 'recursiveFnReturnsPromiseV1 failed';
document.getElementById('v1').appendChild(p);
})
recursiveFnReturnsPromiseV2(aValues, 0)
.then(function() {
let p = document.createElement('div');
p.innerText = 'recursiveFnReturnsPromiseV2 finished';
document.getElementById('v2').appendChild(p);
}, function() {
let p = document.createElement('div');
p.innerText = 'recursiveFnReturnsPromiseV2 failed';
document.getElementById('v2').appendChild(p);
})
function recursiveFnReturnsPromiseV1(pValues, ix) {
if (pValues.length <= ix)
return Promise.resolve();
return new Promise(function(c, e) {
document.getElementById('v1').innerText = ix + 'v1' + Date.now();
c();
}).then(function() {
return recursiveFnReturnsPromiseV1(pValues, ++ix);
})
}
function recursiveFnReturnsPromiseV2(pValues, ix) {
if (pValues.length <= ix)
return Promise.resolve();
return new Promise(function(c, e) {
document.getElementById('v2').innerText = ix + 'v2' + Date.now();
recursiveFnReturnsPromiseV2(pValues, ++ix).then(function() {
c();
}, function(err) {
e()
});
})
}
<div id='v1'></div>
<div id='v2'></div>
推荐答案
让我们去掉 Promise
构造器反模式,并使用简单的 Promise.resolve
代替.你的函数现在变成
Lets strip away the Promise
constructor antipattern, and use a simple Promise.resolve
instead. Your functions now become
function recursiveFnReturnsPromiseV1(pValues, ix) {
if (pValues.length <= ix)
return Promise.resolve();
let p = document.createElement('div');
p.innerText = ix + 'v1' + Date.now();
document.getElementById('v1').appendChild(p);
return Promise.resolve().then(function() {
return recursiveFnReturnsPromiseV1(pValues, ++ix);
})
}
function recursiveFnReturnsPromiseV2(pValues, ix) {
if (pValues.length <= ix)
return Promise.resolve();
let p = document.createElement('div');
p.innerText = ix + 'v2' + Date.now();
document.getElementById('v2').appendChild(p);
return Promise.resolve(recursiveFnReturnsPromiseV2(pValues, ++ix));
}
现在应该很明显为什么第二个函数会溢出堆栈了.
It should be obvious by now why the second function overflows the stack.
为什么不是第一个?因为递归调用在一个异步 then
回调中,这意味着它稍后(在外部调用返回之后)以新的调用堆栈开始.
Why doesn't the first as well? Because the recursive call is inside an asynchronous then
callback, which means it starts later (after the outer call returned) with a fresh call stack.
这篇关于以下模式调用返回承诺的递归 JavaScript 函数有什么区别?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!