最小复现代码:
test.js
function sleep(delay) {
return new Promise(resolve => setTimeout(resolve, delay));
}
const _ = require('lodash');
async function doTask() {
// console.log('start');
await sleep(_.random(10, 30));
// console.log('done');
}
async function start() {
await sleep(3);
await doTask();
await start(); // 去掉前面的await就好了
}
start();
setInterval(() => {
console.log(process.memoryUsage());
},10e3);
进程启动的时候rss是22M,运行了1个多小时后内存占用达到了380M
PID USER PR NI VIRT RES SHR S %CPU %MEM TIME+ COMMAND
30211 devel 20 0 1229m 381m 10m S 1.0 9.6 1:36.63 node test.js
# 在start函数的递归调用中取消await
21729 devel 20 0 867m 23m 10m S 1.0 0.6 1:22.73 node test.js
# 改成循环
14498 devel 20 0 867m 24m 10m S 1.0 0.6 1:11.04 node test.js
虽然确定是在递归调用的时候前面多加了个await,但是能解释下原因么,是我使用的姿势不对么
async 函数返回的是一个 Promise 对象,它是否resolved取决于其中的await是否执行完毕;而await 在 Promise 对象 resolved前会一直阻塞代码运行。再看代码,await start() 中start()是一个async函数,返回的是一个pedding状态的promise,而await 会一直等着这个promise直到resolved,导致start一直进栈,没有出栈:
去掉await后,不需要等着这个promise resolved,start可以正常出栈: