Предоставляет ли JavaScript таймер с высоким разрешением?

Предоставляет ли JavaScript таймер с высоким разрешением?

Я написал несколько игровых движков с нуля, некоторые на C, некоторые на Java, а некоторые на Flash. Я всегда придерживаюсь той же базовой модели, когда речь идет о анимации и интерактивной графике. Создайте базовый класс/структуру со следующим дизайном:

void init() { /* Called once, preload essential resources here. */ }
void update(double time) { /* Updates game/animation state using high resolution time. */ }
void render(double time) { /* Updates screen graphics using high resolution time. */ }

void run()
{
    double time;
    init();
    while (!done)
    {
        time = queryTime();
        update(time);
        render(time);
    }
}

Время настолько важно, чтобы сгладить анимации и вычисления состояния игры. В собственном коде Windows я использую QueryPerformanceCounter() и QueryPerformanceFrequency(), чтобы выполнить роль queryTime() в каждом игровом цикле и передать время для обновления/рендеринга. В Java я использую System.nanoTime().

Что эквивалентно в JavaScript? То есть, некоторая функция типа queryTime(), которая возвращает значение времени с высокой степенью точности (sub millisecond). Из того, что я слышал, лучшая точность, которую вы можете получить в JavaScript, составляет около 15 & middot; ms... что ужасно для анимации.

Ответ 1

См. ниже @h3r3. Это правильный ответ.

Миллисекунды - лучшее, на что можно надеяться в JavaScript. И, как вы сказали, это не очень точно. См. Вопрос о переполнении стека Микросекунды в JavaScript.

timer.js предназначен для обеспечения разрешения до микросекунды, но он доступен только для Google Chrome.

Обновить: timer.js не поддерживает разрешение в микросекундах. Он просто умножает миллисекунд на 1000.

Извините, новостей нет лучше!

Ответ 2

Почти все современные браузеры обеспечивают таймер с высоким разрешением. Это стандарт W3C "Высокое разрешение": http://www.w3.org/TR/hr-time/#sec-DOMHighResTimeStamp.

Это позволяет получить точную метку времени в миллисекундах, вызвав window.performance.now(). Это возвращает метку времени в мс, но она является плавающей точкой, поэтому вы все равно получаете разрешение в миллисекундах.

Очень старые браузеры могут реализовать "префиксную" версию этого стандарта, например. WebKit-браузеры, используемые для реализации window.performance.webkitNow()

Вот какой код вы можете использовать, чтобы получить точную метку времени, когда она доступна, и вернуться к стандартной точности в противном случае:

if (window.performance.now) {
    console.log("Using high performance timer");
    getTimestamp = function() { return window.performance.now(); };
} else {
    if (window.performance.webkitNow) {
        console.log("Using webkit high performance timer");
        getTimestamp = function() { return window.performance.webkitNow(); };
    } else {
        console.log("Using low performance timer");
        getTimestamp = function() { return new Date().getTime(); };
    }
}

getTimestamp();

Обратите внимание, что эта функция getTimestamp() не возвращает значение, которое представляет текущую дату/время. Возвращаемое значение может использоваться только для измерения периодов времени путем вычитания двух разных временных меток. Например.

var t1 = getTimestamp();
//... some other code
var t2 = getTimestamp();
console.log("Time delta: " + (t2 - t1));

Ответ 3

Вместо while (true)/setInterval используйте рекурсивный requestAnimationFrame. Он будет работать более плавно, чем анимация на основе тайм-аута. Он предоставляет временные метки, если вам нужна анимация для работы на более медленном пути.

Ответ 4

На данный момент (25 февраля 2013 г.) качество высокопроизводительных времен в Chrome 24 довольно ужасно.

var old = 0; 

for (var i=0; i<10; i++) {
    var t = window.performance.now(); 
    var d = t - old; 
    old = t; 
    console.log(t + ' += ' +d); 
}

выводит что-то вроде этого:

609689.000000013 += 609689.000000013
609689.9999999441 += 0.9999999310821295
609689.9999999441 += 0
609689.9999999441 += 0
609689.9999999441 += 0
609690.9999999916 += 1.0000000474974513
609690.9999999916 += 0
609690.9999999916 += 0
609691.9999999227 += 0.9999999310821295
609691.9999999227 += 0

Что показывает, что

1) Сэмплирование происходит редко

2) Точность по-прежнему составляет около 1 мс, а не в микросекундах.

Ответ 5

Здесь ваш код должен выглядеть в JavaScript, поэтому он не блокирует пользовательский интерфейс и не использует window.requestAnimationFrame, который не работает кросс-браузер.

/* Called once, preload essential resources here. */
function init() {}

/* Updates game/animation state */
function update(time) {}

/* Updates screen graphics  */
function render(time) {}

window.onload = function()
{
    var time;
    var done = false;

    init();
    // Using setTimeout passing zero makes the animate function run
    // as soon as possible, but yielding first.
    setTimeout(animate, 0);

    function animate () {
        time = new Date();
        update(time);
        render(time);
        if (!done) {
            setTimeout(animate, 0);
        }
    }
}

Проблема с этим подходом заключается в том, что animate() может вызываться чаще, чем экран обновляется (при 60 Гц частота не будет обновляться чаще, чем каждые 16 мск), что вызывает дополнительный рендеринг, который никогда не делает это на экран. Вот почему вы должны придерживаться requestAnimationFrame, если это возможно.

Ответ 6

Node.js также имеет таймер с высоким разрешением.

process.hrtime()

Подробнее см. документацию

Ответ 7

Поскольку это происходит при поиске JavaScript и таймера с высоким разрешением, стоит отметить, что window.performance.now теперь работает (по крайней мере, в Google Chrome против 26) и обеспечивает разрешение ~ микросекунды.

var d = 0;
var p = window.performance;
for(var i=0; i<10; i++) {
    d = -1 * (p.now() - p.now());
    console.log(d*1000);
}

Это дало мне это (в микросекундах):

5.0000089686363935
3.9999722503125668
1.00000761449337
1.00000761449337
1.00000761449337
1.9999861251562834
1.9999861251562834
1.00000761449337
1.00000761449337
0.9999785106629133

Я провел некоторую статистику по нескольким наборам результатов 10k+. Минимум составляет около 1 микросекунды, а среднее составляет около 1,25 микросекунды на моей машине (MacBook Air). Иногда на отметке 100+ микросекунд имеются большие выбросы, но часто наблюдаются более 10 микросекунд.

Таким образом, таймер с высоким разрешением теперь способен вычитать время с разрешением в микросекундах.

Ответ 8

Вы можете использовать преобразования CSS 3 для простых анимаций, которые получат полное аппаратное ускорение и будут работать шелковисто-гладкие в большинстве современных браузеров... Если вы ожидаете плавной анимации на WebGL вам не повезло, потому что на JavaScript не существует субмиллисекундной точности.

В настоящее время существует большой прогресс в предоставлении игровых технологий для Интернета (см., например, проект блокировки мыши, который активно развивает наш полноэкранный API... Возможно, вы можете начать движение для микросекундных таймеров точности в JavaScript; -)

Ответ 9

Помимо уже предоставленных отличных ответов, вы также можете посмотреть marky, a

JavaScript-таймер с высоким разрешением, основанный на показателе производительности/показателя (461 bytes min + gz)

Он также включает в себя средства визуализации инструментов и тестируется в широком диапазоне браузеров.