Javascript 是否有通过使用承诺来避免堆栈溢出的通用技术?

Javascript 是否有通过使用承诺来避免堆栈溢出的通用技术?,javascript,promise,es6-promise,Javascript,Promise,Es6 Promise,我发现一种方法是偶尔“以后再做”: 函数knowNFactorial(n){ 返回新承诺(功能(解决、拒绝){ n=BigInt(n); 如果(n==1n){ 解析(1n); }否则{ 如果(n%1000n!==0n){ knowNFactorial(n-1n)。然后(v=>resolve(n*v)); }否则{ //只是偶尔“以后再做” 设置超时(()=>{ knowNFactorial(n-1n)。然后(v=>resolve(n*v)); }, 0) } } }); } 然后(v=>con

我发现一种方法是偶尔“以后再做”:

函数knowNFactorial(n){
返回新承诺(功能(解决、拒绝){
n=BigInt(n);
如果(n==1n){
解析(1n);
}否则{
如果(n%1000n!==0n){
knowNFactorial(n-1n)。然后(v=>resolve(n*v));
}否则{
//只是偶尔“以后再做”
设置超时(()=>{
knowNFactorial(n-1n)。然后(v=>resolve(n*v));
}, 0)
}
}
});
}
然后(v=>console.log(“我知道它的二进制表示长度是”,v.toString(2.length));
//仅在Node或Google Chrome开发者控制台内执行以下操作:

//然后(v=>console.log(“我知道它是”,v))以递归方式计算阶乘,但避免我们可以使用的最大调用堆栈大小:

  • 一些微任务

    process.nextTick(\u=>f(…)
    /
    Promise.然后(\u=>f(…)
    Promise.最后(\u=>f(…)
    /
    队列任务(\u=>f(…)

(对于节点使用
process.nextTick
,对于浏览器使用
queueTask

  • 一些延迟的宏任务

    setImmediate
    setTimeout
    甚至
    setInterval

(对于节点,使用
setImmediate

  • 相同的执行上下文

    通过蹦床而不是递归叠加


性能由快变慢

  • 如果可能,使其非递归
  • 蹦床
  • 然后是微任务
  • 然后是宏任务(可能是因为每次都进行事件循环)
功能下一个时钟(n、s、cbk){
如果(n==1n){
返回cbk(s)
}
返回进程.nextTick(()=>nextTick(n-1n,s*n,cbk))
}
函数pthen(n,s=1n){
如果(n==1n){
返回s
}
返回Promise.resolve().then(()=>pthen(n-1n,s*n))
}
最终功能(n、s、cbk){
如果(n==1n){
返回cbk(s)
}
//Promise.finally不返回值,您不想使用
//。然后(因为已经包含),所以通过回调返回值
返回Promise.resolve().finally(()=>pffinally(n-1n,s*n,cbk))
}
功能微任务(n、s、cbk){
如果(n==1n){
返回cbk(s)
}
return queueMicrotask(()=>microtask(n-1n,s*n,cbk))
}
立即函数(n、s、cbk){
如果(n==1n){
返回cbk(s)
}
return setImmediate(()=>immediate(n-1n,s*n,cbk))
}
功能超时(n、s、cbk){
如果(n==1n){
返回cbk(s)
}
return setTimeout(()=>timeout(n-1n,s*n,cbk),0)
}
功能间隔(n、s、cbk){
//感觉像蹦床,但让引擎给我们回电话,而不是明确地这样做
arg1=n
arg2=s
常量id=setInterval(函数(){
如果(arg1==1n){
清除间隔(id)
返回cbk(arg2)
}
arg2=arg1*arg2
arg1=arg1-1n
}, 0.01)
}
功能总拥有成本(n,s=1n){
如果(n==1n){
返回s
}
返回tco(n-1n,s*n)
}
功能域(n){
函数不规则波(n,v=1n){
如果(n==1n){
返回v
}
返回=>trampo(n-1n,n*v)
}
设f=流浪汉(n)
while(typeof f==‘function’){
f=f()
}
返回f
}
函数cbkToProm(f){
返回n=>newpromise((解析,拒绝)=>f(n,1n,解析))
}
;(异步=>{
常量方法={
然后,
最终:cbkToProm(最终),
蹦床
}
if(进程类型==='object'){
methods.nextTick=cbkToProm(nextTick)
}
if(typeof setImmediate==='function'){
methods.setImmediate=cbkToProm(立即)
}
if(queueMicrotask的类型=='function'){
methods.queueMicrotask=cbkToProm(microtask)
}
//慢得可怕
methods.setTimout=cbkToProm(超时)
methods.setInterval=cbkToProm(interval)
//不起作用
methods.tco=tco
常数N=BigInt(1e9)+7n
for(Object.entries(methods))的常量[name,f]{
控制台时间(名称)
log('res',parseInt((等待f(2000n))%N))
console.timeEnd(名称)
}

})()
目前我不知道这些是观点还是基于一些常见做法或标准做法。。。你能引用一些参考资料或帖子吗?我认为这既不是常见的也不是标准的做法,因为对于大型递归,可能会采用迭代的方式。对于非性能关键的东西,可以使用宏任务来避免。我仍然没有链接,这篇文章只是针对那些不适合讨论的评论而创建的;这段对话已经结束。