比如下面这个例子,递归次数在100的时候,还没有问题。
一旦执行100000次的时候就会发生递归栈溢出的问题。
function sum0(total, i, callback) {
if(i===0){
callback(total);
return;
}
sum0(total+i, i-1, callback)
}
sum0(0, 100, value=>{
console.log(value)
})
sum0(0, 100000, value=>{
console.log(value)
})
每次sum0都会执行sum0,导致调用栈中sum0过多溢出。
可用setTimeout,解决调用栈过多的问题:
function sum0(total, i, callback) {
if(i===0){
callback(total);
return;
}
// sum0(total+i, i-1, callback)
setTimeout(sum0, 0, total+i, i-1, callback)
}
sum0(0, 100, value=>{
console.log(value)
})
sum0(0, 100000, value=>{
console.log(value)
})
但是问题是,要等很久才能出结果。
这个原理是,当sum0运行到setTimeout处,任务被存至回调队列,然后sum0被返回,sum0执行完被弹出调用栈,任务队列的任务再进入调用栈中运行,所以每次调用栈中只能运行一次sum0。不过,任务加入任务队列再到调用栈有一定延迟,一般为几毫秒到十几毫秒不等,如果按照10毫秒计算,100000个任务就要10ms*100000=1000s了。所以会迟迟不出结果。
解决办法:
function sum2(total, i, callback) {
if(i===0){
callback(total);
return;
}
let part = 1000;
if(i%part ===0 ){
setTimeout(sum2, 0, total+i, i-1, callback)
}else{
sum2(total+i, i-1, callback)
}
// sum0(total+i, i-1, callback)
}
sum2(0, 100000, value=>{
console.log(value)
})
原理是:每1000次调用sum2,才会执行一次setTimeout,sum2才会被安排到任务队列中,同时调用栈不会溢出。