为什么setInterval()给出循环引用?

时间:2018-07-25 19:26:31

标签: javascript node.js typeerror circular-reference stringify

考虑以下代码:

let id = setInterval(function f() {console.log("Nice.");}, 1000);
console.log(id);
JSON.stringify(id);

此操作在最后一行显示TypeError: Converting circular structure to JSON时出错。

console.log(id)给出

Timeout {
  _called: false,
  _idleTimeout: 1000,
  _idlePrev: 
   TimersList {
     _idleNext: [Circular],
     _idlePrev: [Circular],
     _timer: Timer { '0': [Function: listOnTimeout], _list: [Circular] },
     _unrefed: false,
     msecs: 1000,
     nextTick: false },
  _idleNext: 
   TimersList {
     _idleNext: [Circular],
     _idlePrev: [Circular],
     _timer: Timer { '0': [Function: listOnTimeout], _list: [Circular] },
     _unrefed: false,
     msecs: 1000,
     nextTick: false },
  _idleStart: 81,
  _onTimeout: [Function: f],
  _timerArgs: undefined,
  _repeat: 1000,
  _destroyed: false,
  [Symbol(asyncId)]: 6,
  [Symbol(triggerAsyncId)]: 1 }

为什么超时对象包含循环引用?

3 个答案:

答案 0 :(得分:2)

请注意,node.js中的setInterval与javascript中的setInterval行为不同。虽然javascript版本返回整数,但node.js returns a Timeout object.并不用于序列化。

答案 1 :(得分:1)

Timeout object包含对自身的引用(可以通过id.ref()访问)

您实际上可以在console.log()输出中看到它:

TimersList {
  _idleNext: [Circular],
  _idlePrev: [Circular],
  _timer: Timer { '0': [Function: listOnTimeout], _list: [Circular] },
  _unrefed: false,
   msecs: 1000,
   nextTick: false },
_idleNext: 

您无法使用JSON.stringify()对其进行序列化,因为该对象包含对自身的引用,并且该对象也包含对自身的引用,并且该对象也包含对自身的引用(请参阅我要去的地方)在这里?)

答案 2 :(得分:1)

如果要“序列化”超时对象,则可以使用如下的帮助程序类。这将通过将超时存储在内部TimeoutHelper.timeouts字段中来序列化超时,并返回一个ID,您以后可以使用TimeoutHelper.clearTimeout(i)对其进行调用:

let TimeoutHelper = (() => {
  let helper = {};
  let counter = 0;
  let timeouts = {};
  
  helper.setInterval = (fn, ms) => {
    let currCounter = counter++;
    
    timeouts[currCounter] = window.setInterval(fn, ms);
    
    return currCounter;
  }
  
  helper.clearTimeout = (id) => {
    if (typeof timeouts[id] === 'undefined') {
      return; // Mimic window.clearTimeout, and silently return if the ID doesn't exist
    }
    window.clearInterval(timeouts[id]);
    delete timeouts[id];
  }
  
  return helper;
})();

var i = TimeoutHelper.setInterval(() => console.log('test'), 1000);

console.log(`Serialized TimeoutHelper id: ${i}`);

setTimeout(() => {
  console.log(`Clearing Timeout: ${i}`);
  TimeoutHelper.clearTimeout(i);
}, 5000);