清除 NodeJS 超时时函数未运行完成

问题描述 投票:0回答:1

好吧 - 所以我已经写了这个并且它按照我想要的方式工作,我只是不明白它是如何工作的/为什么它按照它的方式工作。

有人可以解释一下我在这里缺少什么吗?

这是代码:

const crypto = require('crypto');

class ProcessController extends AbortController {
  timeouts = new Map();

  sleep(ms) {
    const id = crypto.randomBytes(8).toString('hex');
    return new Promise((resolve) => {
      this.timeouts.set(id, setTimeout(() => {
        this.timeouts.delete(id);
        resolve();
      }, ms))
    })
  }

  abort() {
    super.abort();
    for (const timeout of this.timeouts.values()) {
      clearTimeout(timeout);
    }
    // not really necessary as not reusable but be tidy
    this.timeouts.clear();
  }
}

async function meLoop(controller) {
  const { signal } = controller;

  while (!signal.aborted) {
    console.log("START OF LOOP. Uptime:", Math.floor(process.uptime()));
    await controller.sleep(5 * 1000);
    console.log('END OF LOOP');
  }
  console.log("BEYOND LOOP. Uptime:", process.uptime());
}

async function main() {
  const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
  const controller = new ProcessController();
  meLoop(controller);
  await sleep(23 * 1000);
  controller.abort();

  console.log("END. Uptime:", process.uptime());
}

main();

结果如下:

> node testBreakSleep.js
START OF LOOP. Uptime: 0
END OF LOOP
START OF LOOP. Uptime: 5
END OF LOOP
START OF LOOP. Uptime: 10
END OF LOOP
START OF LOOP. Uptime: 15
END OF LOOP
START OF LOOP. Uptime: 20
END. Uptime: 23.044878139

基本上,这是一个可中止的循环。我的理解是,在 while 循环期间,其中的任何内容都应该在再次评估 while 之前运行完成,因为 Javascript 是单线程的。

但是,我不明白的是,当调用

abort()
并且清除
setTimeout
时,它只是退出而不是完成循环?我不明白承诺会发生什么?它无法解析,并且永远不会到达循环末尾(这对我来说有好处)

有人可以解释一下吗?

编辑 - 我想我应该提到,如果我注释掉

clearTimeout
函数中的
abort()
,Node 会一直挂起,直到承诺解决。

> node testBreakSleep.js
START OF LOOP. Uptime: 0
END OF LOOP
START OF LOOP. Uptime: 5
END OF LOOP
START OF LOOP. Uptime: 10
END OF LOOP
START OF LOOP. Uptime: 15
END OF LOOP
START OF LOOP. Uptime: 20
END. Uptime: 23.037329278
END OF LOOP
BEYOND LOOP. Uptime: 25.041987186

谢谢

javascript while-loop promise abortcontroller
1个回答
0
投票

meLoop()
来电时

await controller.sleep(5 * 1000);

该函数将暂停,直到

sleep()
中的超时结束并调用
resolve()

当您清除

ProcessController.abort()
中的超时时,它永远不会调用
resolve()
,因此
await
语句永远不会完成,循环将永远挂起。

© www.soinside.com 2019 - 2024. All rights reserved.