Есть ли что-то быстрее, чем setTimeout и requestAnimationFrame?

(Мне нужен эквивалент process.nextTick в браузере.)

Я пытаюсь максимально использовать производительность javascript, поэтому я сделал простой счетчик... Через секунду я делаю непрерывные вызовы функции, которая просто добавляет ее к переменной.

Код: codepen.io/rafaelcastrocouto/pen/gDFxt

Я получил около 250 с setTimeout и 70 с requestAnimationFrame в google chrome/win7. Я знаю, что requestAnimationFrame идет с частотой обновления экрана, поэтому, как мы можем сделать это быстрее?

PS: Я знаю asm.js

Ответ 1

Хорошо, там setImmediate(), который запускает код немедленно, т.е. как вы ожидали бы получить с помощью setTimeout(0).

Разница в том, что setTimeout(0) фактически не запускается немедленно; setTimeout "зажимается" до минимального времени ожидания (4 мс), поэтому вы получаете только 250 баллов в тестовой программе. setImmediate() действительно работает сразу, поэтому ваш счетчик теста будет на порядок выше, используя его.

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

postMessage() также является вариантом, и он может достичь почти одинаковых результатов, хотя это более сложный API, поскольку он предназначен для более многого, чем просто простой цикл вызова. Плюс есть другие соображения, которые следует учитывать при его использовании (см. Связанную статью MDN для более).

На сайте MDN также упоминается библиотека polyfill для setImmediate, которая использует postMessage и другие методы для добавления setImmediate в браузеры, которые не поддерживайте его еще.

С requestAnimationFrame() вы должны получить 60 для вашей тестовой программы, так как это стандартное число кадров в секунду. Если вы получаете больше, чем это, то ваша программа, вероятно, работает более чем на секунду.

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

Вот почему requestAnimationFrame() существует. Если все, о чем вы заботитесь, это заставить ваш код работать как можно чаще, то не используйте requestAnimationFrame(); вместо этого используйте setTimeout или setImmediate. Но это не всегда лучшая вещь для производительности, потому что она будет потреблять мощность процессора, которую браузер нуждается в других задачах.

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

Ответ 2

Самая короткая возможная задержка при по-прежнему асинхронная - от MutationObserver, но она настолько коротка, что если вы просто продолжаете ее называть, пользовательский интерфейс никогда не сможет обновиться.

Таким обманом было бы использовать MutationObserver для увеличения значения при одновременном использовании requestAnimationFrame для обновления пользовательского интерфейса, но это не разрешено.

Какая немая конкуренция.

См. http://jsfiddle.net/6TZ9J/1/

var div = document.createElement("div");
var count = 0;
var cur = true;
var now = Date.now();
var observer = new MutationObserver(function () {
    count++;
    if (Date.now() - now > 1000) {
        document.getElementById("count").textContent = count;
    } else {
        change();
    }

});

observer.observe(div, {
    attributes: true,
    childList: true,
    characterData: true
});

function change() {
    cur = !cur;
    div.setAttribute("class", cur);
}
change();