【问题标题】:What is Symbol(asyncId) and can you use it to clear intervals?什么是 Symbol(asyncId),你能用它来清除间隔吗?
【发布时间】:2020-07-21 05:27:32
【问题描述】:

我在 NodeJS 中使用 setInterval(),发现它返回了一个包含一些信息的 Timeout 对象,其中之一是 Symbol(asyncId)

什么是Symbol(asyncId),是否可以将其用作对clearInterval() 的区间的引用?如果有,怎么做?

这是我当前的代码:

interval = setInterval(async function () {
    prepareObj(message);
    console.log(interval);
    const intervalID = Reflect.ownKeys(interval).find(
      (key) => key.toString() === "Symbol(asyncId)"
    );
    await saveID(message, interval[intervalID]);
  }, 5000);

setInterval() 正在运行多次,我需要另一种方法来清除每个单独的间隔,因为 interval 将被重新分配以包含最新的 Timeout 对象。我尝试将Symbol(asyncId) 的值存储在 SQLite DB 中,以便稍后访问该值以清除间隔但没有成功。

地图尝试

let intervals = new Map();
interval = setInterval(async function () {
    prepareCard(message);
    console.log(interval);
    await saveID(message, interval);
  }, 5000);

async function saveID(message, id) {
  intervals.set(`${message.channel.id}`, { interval });
}

// Clearing interval
const objToClear = intervals.get(channel);
console.log(objToClear);
const clear = clearInterval(objToClear["interval"]);
console.log(clear);

调用clearTimeout()时,我只清除最近设置的区间,而不是目标区间。

【问题讨论】:

  • 是的,无论 setInterval 返回什么,您都可以使用 clearInterval。
  • 鉴于it's not documented,我强烈建议不要这样做。为什么除了 Timeout 对象之外还需要其他引用?
  • 我不确定你使用的是什么浏览器,但是返回值通常是一个数值,符号是一个唯一的标识符,要获得一个你需要原始符号的值。我们可能需要更多的上下文。
  • 他使用的是node.js,而不是浏览器,它确实是一个对象。但使用模式完全一样。
  • 查看这个答案。我认为他们正在做你想做的事。 stackoverflow.com/a/51526843/1495198

标签: javascript node.js sqlite serialization settimeout


【解决方案1】:

什么是Symbol(asyncId)

在定时器上实现async hooks是node.js的internal symbol used in the timer implementation

……你能用它来清除间隔吗?

没有。 没有查找表afaics,即使有你也不应该乱用它。见下文。

我需要在 SQLite DB 中存储一个值,以便稍后访问该值以清除间隔。

您可以为此想出自己的 ID:

import * as timers from 'timers';

let counter = 0;
const intervals = new Map();

export function setInterval(callback, delay, ...args) {
  const timer = timers.setInterval(callback, delay, ...args);
  timeouts.set(++counter, timer);
  return counter;
}
export function clearInterval(id) {
  const timer = intervals.get(id);
  timers.clearInterval(timer);
  return intervals.delete(id);
}

但是,我刚刚注意到有一个 recent commit(2020 年 6 月)允许将 Timer 实例用作对象中的键,从而提供一种将它们强制为数字的方法:

const timer = setInterval(…);
const id = Number(timer);
…
clearInterval(id);

不确定什么时候发布:-)

一般注意事项:计时器 ID 不是全局唯一的,而是仅针对每个线程和程序的执行。要将它们存储在外部数据库中,这意味着您必须在应用程序启动时删除所有 id,否则它们会悬空。理想情况下,这永远不会发生在所有计时器都被清除并且数据库对它们的引用被删除的干净关闭中,但您永远无法确定。为了缓解这个问题,您还可以在存储在数据库中的 id 前面加上一个 db 连接 id 或存储在数据库中的其他内容,并且每次启动时都会递增。

【讨论】:

  • 这个解决方案和 Keith 提供的解决方案在这种情况下被证明是最好的。向所有提供帮助的人致敬!
【解决方案2】:
// this will print "hi" to your console every second
const myIntervalId = setInterval(() => console.log("hi"), 1000);

// this will stop the "hi" from being printed 
clearInterval(myIntervalId)

有趣的事实...setTimeout 也返回一个 id,并与 setInterval 共享相同的 id 命名空间,因此您可以使用 clearInterval 清除来自 setTimeout 的 id!

【讨论】:

  • 是的,我知道您可以将间隔设置为变量并以这种方式清除。但是是否可以使用其他方式清除它,即使用 Symbol(asyncId) 的值?
  • myIntervalId 不是 id,它是一个对象。
  • @Bergi 如果我没记错的话,一些早期版本的 javascript 返回了一个整数。我过去常常传递“看起来”像 setInterval 返回的东西的数值的数字来清除计时器并且它起作用了。不知道它有多远,但今天是我第一次了解到 setInterval 返回一个 Timeout 对象
  • 是的,我也是新手。但无论如何,语义是相同的。您可以将它们视为 id。
  • @slebetman 这就是它在 DOM 中的工作方式,但 node.js 确实(从那时起就是 afaik)使用计时器对象。
猜你喜欢
  • 1970-01-01
  • 2022-12-05
  • 1970-01-01
  • 2012-03-05
  • 2010-09-13
  • 1970-01-01
  • 2011-03-23
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多