有和没有睡眠的递归异步

ami*_*mar 8 javascript

我有两个版本的异步函数

async function asyncRecurseOne(i){
    try{
        console.log(i)
        i = i +1;
        await asyncRecurseOne(i)
    }catch(ex){
        console.log(ex);
    }
}

asyncRecurseOne(0);
Run Code Online (Sandbox Code Playgroud)

这导致最大调用堆栈大小超过 6300 左右

6246
6247
6248
RangeError: Maximum call stack size exceeded
    at asyncRecurseOne (/home/amit/Projects/NodeJs/MJS/recurse.js:38:17)
    at asyncRecurseOne (/home/amit/Projects/NodeJs/MJS/recurse.js:36:15)
Run Code Online (Sandbox Code Playgroud)

现在在另一个版本中,我使用 sleep 方法执行以下操作

let sleep = (time) => new Promise((resolve) => setTimeout(resolve, time))
async function asyncRecurseTwo(i){
    try{
        console.log(i)
        i = i +1;
        await sleep(100);
        await asyncRecurseTwo(i)
    }catch(ex){
        console.log(ex);
    }
}
Run Code Online (Sandbox Code Playgroud)

而且这个函数没有给出解决问题的最大调用堆栈大小,我在我的系统上运行直到记录了 20000。

第二个函数如何在不达到最大堆栈大小问题的情况下继续执行?

Nic*_*wer 9

async函数同步执行,直到它们遇到await,此时它们返回一个承诺。你的第一段代码在这一行有它唯一的等待:

await asyncRecurseOne(i)
Run Code Online (Sandbox Code Playgroud)

要评估这一行,它需要调用asyncRecurseOne,获取返回值,然后才会执行await。所以它会同步递归,下次通过函数会做同样的事情,构建一个越来越大的调用堆栈,直到你得到异常。它永远不会到达await.

你的另一个案例没有这个问题。它使它成为这一行:

await sleep(100);
Run Code Online (Sandbox Code Playgroud)

sleep 创建并返回一个承诺。然后它击中await,因此您的函数返回它自己的承诺。没有增加调用堆栈。100 毫秒后,它恢复并递归,但是这个新的递归具有相同的中断,因此调用堆栈不会继续增长。