Почему setInterval () дает циклическую ссылку?

Учитывая следующий код:

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

Это заканчивается ошибкой в ​​последней строке с сообщением TypeError: Converting circular structure to JSON.

console.info(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 }

Почему объект Timeout содержит циклическую ссылку?

Зачем вы его JSON.stringify?

Kevin B 25.07.2018 21:32
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
1
657
3

Ответы 3

Объект тайм-аута содержит ссылку на себя (доступ к которой можно получить с помощью id.ref())

Вы можете увидеть это в выводе console.info():

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

Вы не можете сериализовать его с помощью JSON.stringify(), потому что объект содержит ссылку на себя, и этот объект также содержит ссылку на себя, и этот объект также содержит ссылку на себя (см., Куда я иду?)

Да, я видел там Circular. Мой главный вопрос: Зачем?

kramer65 25.07.2018 21:53

@ kramer65 Я обновил свой вопрос. По сути, невозможно сериализовать какой-либо объект, содержащий ссылку на себя.

Daniel 25.07.2018 21:58

Я понимаю это, но мой вопрос был больше: почему он содержит ссылку на себя? В чем причина этой циркулярной ссылки?

kramer65 26.07.2018 07:30

Обратите внимание, что setInterval в node.js ведет себя иначе, чем setInterval в javascript. Хотя версия javascript возвращает целое число, node.js возвращает объект Timeout. и не предназначена для сериализации.

Если вы хотите «сериализовать» объект тайм-аута, вы можете использовать вспомогательный класс, как показано ниже. Это будет сериализовать таймауты, сохраняя их во внутреннем поле TimeoutHelper.timeouts, и вернет идентификатор, который вы позже можете вызвать с помощью 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.info('test'), 1000);

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

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

Другие вопросы по теме