16 June 2015

Наблюдение за работой JavaScript-таймеров в реальном времени

Website developmentJavaScript
Визуализация динамического процесса на графике — один из способов получения новой/дополнительной информации. В публикации показана простая утилита, с помощью которой можно увидеть работу JavaScript-таймеров. С одной стороны, JavaScript-таймеры хорошо подходят для организации циклического процесса. С другой стороны, они, в общем виде, наглядно демонстрируют поведение однопоточной JavaScript-многозадачности, что, в ряде случаев, тоже может быть полезным.

Изображение - JavaScript-таймеры

График позволяет:
  • Увидеть работу JavaScript-таймера в реальном времени.
  • Смоделировать разные условия нагрузки.
  • Сравнить работу разных браузеров.
  • Даёт информацию к размышлению (некоторые результаты оказались любопытными).


Введение


По горизонтальной оси (X) измеряется количество пройденных циклов. По вертикальной оси (Y) измеряется время в миллисекундах (мс). Начало — по кнопке «СТАРТ». Завершение — происходат автоматически, после визуального заполнения данных по оси X.

Измеряемые значения:
  • Красный: промежуток времени от начала одного цикла до начала другого (время полного цикла).
  • Белый: промежуток времени от окончания одного цикла до начала другого (время задержки).
  • Синий: время видеонагрузки. Видеонагрузкой является графическое отображение этого графика.
  • Циан: время псевдонагрузки. Псевдонагрузкой является простое циклическое повторение JavaScript-кода.

Работоспособность проверялась:
  • Windows: FF, OPERA, CR, IE.
  • Linux: FF, OPERA.

Код на GitHub.
Демо на GitHub (так-же работает с диска).

Типы таймеров


setTimeout

setTimeout используется для разовых задержек исполнения кода и для организации циклов. Цикл на основе setTimeout:
MyFunc = function () {
   
   // прикладной код
     
   setTimeout(function () {
            MyFunc();
       }, 100);
}

Здесь всё, вроде-бы, очевидно: 100 — это задержка в миллисекундах (мс), через которую будет запущен следующий цикл задания. Но, при организации цикла, интуитивно ожидаешь, что код будет выполняться именно с этим периодом. На самом деле (видно на графике), фактическое время цикла будет состоять из времени выполнения кода плюс времени задержки. То есть, чем сложнее код — тем длиннее будет фактическое время цикла.

setInterval

setInterval используется для исполнения кода через определённые промежутки времени. Цикл на основе setInterval:
MyTimer = function () {
    setInterval(function () {
            MyFunc(); // прикладной код
        }, 100);
}

На графике видно, что setInterval контролирует время полного цикла. При изменении времени выполнения кода, «интеллектуально» корректируется время между вызовами так, чтобы время полного цикла оставалось стабильным. Если время выполнения кода, превышает заданный период, то таймер, исчерпав возможности по уменьшению времени между вызовами, начинает вызываться с удлинённым периодом.

requestAnimationFrame

requestAnimationFrame используется для циклической перерисовки экрана, которая синхронизирована с циклами перерисовки браузера. Цикл на основе requestAnimationFrame:
MyFunc = function () {
   
   // прикладной код
     
    requestAnimationFrame(function () {
            MyFunc();
        });
}


setTimeout/setInterval + requestAnimationFrame

Теоретически, гибридные решения должны были совместить возможности точного таймирования и синхронизации отрисовки с циклом обновления экрана. Цикл на основе setTimeout + requestAnimationFrame:
MyFunc = function () {
   
   // прикладной код

    setTimeout(function () {
       requestAnimationFrame(function () {
              MyFunc();
           });
      }, 100);
}

Цикл на основе setInterval + requestAnimationFrame:
MyTimer = function () {
    setInterval(function () {
        requestAnimationFrame(function () {
               MyFunc(); // прикладной код
            });
        }, 100);
}

Функционально код выполняется, но, при этом, наблюдается повышенная нестабильность периодов циклов.

Наблюдения:
  • Для разных браузеров поведение таймеров может отличаться. Особенно это проявляется при низких значениях времени задержки и/или при повышенных нагрузках.
  • Если в браузере, с закладки с графиком перейти на другую закладку (в том-же окне), то работа таймеров останавливается, и снова возобновляется после активизации закладки с графиком. Если же открыть в браузере другое окно, то работа таймеров не прекращается.


Видеонагрузка


В качестве видеонагрузки используются функции отрисовки графика на Canvas.

При выборе простой функции (APELSERG.CANVA.Paint), сетка графика отрисовывается один раз, при старте. И, далее, в процессе построения графика, выводится только текущий результат (четыре точки) и счётчик циклов.

При выборе сложной функции (APELSERG.CANVA.PaintComplex), все результаты сохраняются в массивы. Каждый раз при отрисовке, заново обновляется сетка графика и выводятся все сохранённые результаты из всех массивов.

Псевдонагрузка


Псевдонагрузка — это простой цикл на JavaScript, в котором выбирается случайное значение:
APELSERG.MAIN.VirtCalc = function () {
    for (var n = 0; n < APELSERG.CONFIG.SET.TypeVirtCalc ; n++) {
        var q = Math.round(Math.random() * 100);
    }
}

Цикл вынесен в отдельную функцию, чтобы проще можно было подставить другой код. Можно выбрать количество циклов от 0 до 1 000 000 000. Результат тестирования под псевдонагрузкой, в разных браузерах, немного удивил.

Масштабирование и сохранение графика


Чтобы изменить масштаб сетки, надо:
  1. Изменить масштаб отображения браузера (Ctrl-, Ctrl+).
  2. Перезагрузить страницу.
  3. Выбрать размер вывода значения (от 1 до 4 px).


Полученный график можно сохранить как стандартное изображение:
  1. Правая кнопка мыши на графике.
  2. Сохранить изображение как...


Полезные ссылки


Основной цикл в Javascript
О том, как работают JavaScript таймеры
Tags:web-разработкаjavascriptbrowserstimerinterval
Hubs: Website development JavaScript
+8
7.7k 66
Comments 6
Top of the last 24 hours