Как я могу показать список всех потоков, созданных setTimeout/setInterval

Я хочу сделать это либо чистым javascript, либо любой консолью в браузере или что-то еще.

Возможно ли это?

Спасибо

Дальнейшие объяснения: Я хочу отлаживать библиотеку, которая выполняет анимацию. Я хочу знать, создано ли несколько таймеров, если есть несколько анимированных объектов.

Ответы

Ответ 1

Как уже упоминалось, setTimeout не создает поток. Если вам нужен список всех идентификаторов таймаута (например, вы можете их отменить), то см. Ниже:


Я не думаю, что вы можете получить список всех идентификаторов timeout без изменения кода при их вызове. setTimeout возвращает id, и если вы его игнорируете, то это недоступно для вашего JavaScript. (Очевидно, у переводчика есть доступ к нему, но ваш код этого не делает.)

Если вы можете изменить код, вы можете это сделать:

var timeoutId = [];

timeoutId.push(setTimeout(myfunc, 100));

... Убедитесь, что timeoutId объявлен в глобальной области (возможно, используя window.timeoutId = []).


Сверху моей головы, но для переопределения setTimeout вам нужно сделать что-то вроде этого:

var oldSetTimeout = setTimeout;
setTimeout = function (func, delay) {
    timeoutId.push(oldSetTimeout(func, delay));
}

Это не проверено, но оно дает вам отправную точку. Хорошая идея, волк!

Изменить: ответ aularon дает гораздо более полное воплощение вышеуказанной идеи.

Ответ 2

Обратите внимание, что setTimeout() не создает новые потоки. Сценарий на стороне браузера не только однопоточный, но и оценка JavaScript разделяет один и тот же единственный поток с рендерингом страницы (веб-работники).

Дальнейшее чтение:

Вы можете сами создать диспетчер таймера:

var timerManager = (function () {
   var timers = [];
   return {
      addTimer: function (callback, timeout) {
         var timer, that = this;
         timer = setTimeout(function () {
            that.removeTimer(timer);
            callback();
         }, timeout);
         timers.push(timer);
         return timer;
      },
      removeTimer: function (timer) {
         clearTimeout(timer);
         timers.splice(timers.indexOf(timer), 1);
      },
      getTimers: function () {
         return timers;
      }
   };
})();

Затем используйте его следующим образом:

var t1 = timerManager.addTimer(function () {
   console.log('Timer t1 triggered after 1 second');
}, 1000);

var t2 = timerManager.addTimer(function () {
   console.log('Timer t2 triggered after 5 second');
   console.log('Number of Timers at End: ' + timerManager.getTimers().length);
}, 5000);

console.log('Number of Timers at Start: ' + timerManager.getTimers().length);

Вышеуказанный результат отобразит следующий результат в консоли:

// Number of Timers at Start: 2
// Timer t1 triggered after 1 second
// Timer t2 triggered after 5 second
// Number of Timers at End: 0

Обратите внимание, что вышеприведенная реализация timerManager использует метод Array.indexOf(). Это было добавлено в JavaScript 1.6 и поэтому не реализовано всеми браузерами. Однако вы можете легко добавить этот метод самостоятельно, добавив реализацию из этой статьи Mozilla Dev Center.

Ответ 3

Наконец, это было интересно для меня, поэтому я потратил некоторое время на то, чтобы придумать что-то, и вот он

Он переопределяет браузер setTimeout и заполняет активное состояние текущих активных вызовов в хеше window._activeSetTimeouts, с демонстрационной функцией window._showCurrentSetTimeouts(), которая отображает текущие ожидающие вызовы setTimeout.

if(typeof window._setTimeout =='undefined') {
window._setTimeout=window.setTimeout;

window._activeSetTimeouts={};
window._activeSetTimeoutsTotal=0;
window._setTimeoutCounter=0;
window._showCurrentSetTimeouts=function() {
    var tgt=document.getElementById('_settimtouts');
    if(!tgt) {
    tgt=document.createElement('UL');
    tgt.style.position='absolute';
    tgt.style.border='1px solid #999';
    tgt.style.background='#EEE';
    tgt.style.width='90%';
    tgt.style.height='500px';
    tgt.style.overflow='auto';
    tgt.id='_settimtouts';

    document.body.appendChild(tgt);
    }

    tgt.innerHTML='';
    var counter=0;
    for(var i in window._activeSetTimeouts) {
        var li=document.createElement('LI');
        li.innerHTML='[{status}] {delay} ({calltime})<br /><pre style="width: 100%; height: 5em; overflow: auto; background: {bgcolor}">{cb}</pre>'.f(window._activeSetTimeouts[i]);
        li.style.background=(counter++%2)?'#CCC' : '#EEB';
        tgt.appendChild(li);
    }
}
window.setTimeout=function(cb, delay) {
    var id = window._setTimeoutCounter++;
    var handleId = window._setTimeout(function() {
    window._activeSetTimeouts[id].status='exec';
    cb();
    delete window._activeSetTimeouts[id];
    window._activeSetTimeoutsTotal--;
    }, delay);

    window._activeSetTimeouts[id]={
    calltime:new Date(),
    delay:delay,
    cb:cb,
    status:'wait'
    };
    window._activeSetTimeoutsTotal++;
    return id;
}

//the following function is for easy formatting

String.prototype.f=function(obj) {
var newStr=this+'';
if(arguments.length==1) {
if(typeof(obj)=='string') {
    obj={x:obj};
}


for(var i in obj) {
    newStr=newStr.replace(new RegExp('{'+i+'}', 'g'), obj[i]+'');
}
newStr+='';

} else {
    for(var i=0; i<arguments.length; i++) {
    newStr=newStr.replace('{'+(i+1)+'}', arguments[i]);
    }
}
return newStr;
}
}

//following line for test
for(var i=0; i<5; i++) setTimeout(window._showCurrentSetTimeouts, 3000*i);