Можем ли мы считать requestAnimFrame «выходом» в цикле приложения, чтобы разрешить обработку цикла событий?

Я использую requestAnimFrame метод в JavaScript, чтобы сделать свой холст обновить в основном цикле моей программы:

window.requestAnimFrame = (function(callback) {
  return window.requestAnimationFrame || window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame ||
    function(callback) {
      window.setTimeout(callback, 1000 / 60);
    };
})();


function animate() {
    requestAnimationFrame( animate );
//var runcount = 100;
//for (var i=0;i<=100;i++) {
    draw();
//    if (runcount === i)
//        alert("Completed program loop");
//    }
}

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

Тот факт, что холст не обновлялся до завершения моей программы, заставил меня думать, что обновление холста выполнялось в другом потоке, который не получил приоритета. (Но мы знаем, что JavaScript является однопоточным).

Мой вопрос: Можем ли мы рассматривать requestAnimFrame как «выход» в цикле приложения, чтобы разрешить обработку цикла событий? Могу ли я по-прежнему предполагать, что JavaScript является однопоточным?


person hawkeye    schedule 09.01.2014    source источник
comment
Он ничего не меняет, это просто держатель обратного вызова для вашего кода. И да, JS по-прежнему однопоточный.   -  person zerkms    schedule 09.01.2014
comment
ваш вопрос не ясен. он ничего не обновляет. Не очевидно, что вы имеете в виду, говоря, почему он не обновил холст, когда он все равно работал.   -  person zerkms    schedule 09.01.2014
comment
я отредактировал, чтобы ответить на ваше редактирование.   -  person GameAlchemist    schedule 10.01.2014


Ответы (1)


Вы не конкретизируете, как вы выполнили свою итерацию 1000 раз, но я предполагаю, что вы имеете в виду, что вы итерировали, используя цикл for или while (? Поправьте меня, если я ошибаюсь..).

Когда вы выполняете цикл for/while, сценарий будет зацикливаться до тех пор, пока этот цикл (или область действия) не завершится. Поскольку JS, как вы знаете, является однопоточным, он не может обрабатывать такие вещи, как очередь событий, пока он это делает, поэтому ничто не сможет обновляться (включая DOM) до тех пор, пока цикл не завершится (вообще говоря, могут быть специфичные для браузера реализация, которая разрешает обновления DOM, если обновления DOM выполняются, например, в отдельном потоке, но это отдельная вещь от JS).

Теперь, когда вы реализовали rAF, вы выполняете одну итерацию для каждого кадра. Это означает, что у браузера есть время для обработки очереди событий асинхронно (не то же самое, что многопоточность), если только код, который вы обрабатывали в цикле, также некоторое время не выполнял цикл занятости, который создал бы тот же сценарий. как первый.

Вы могли бы также использовать setTimeout. Чем отличается rAF от, например, setTimeout или setInterval, так это тем, что это эффективная низкоуровневая реализация механизма таймера, способного синхронизироваться с VBLANK (вертикальное гашение, которому видеокарта подчиняется с помощью параметра, называемого vsync) — простым словом означает частоту обновления монитора (обычно 60 Гц). Это позволяет нам создавать плавную анимацию, и именно поэтому она называется request*Animation*Frame, поскольку именно для этого она в первую очередь и создана.

Является ли JS все еще однопоточным? Да, это не изменится (единственный способ добиться многопоточности в JS — использовать Web Workers).

РАФ что-то меняет? Не в этой области - это более точная и производительная альтернатива setTimeout, и она синхронизируется по-другому, но это все. На него будут распространяться те же ограничения, что и на setTimeout, который не сможет запускаться, если область занята (отсюда часть имени request*, которая не подразумевает гарантии), но когда он сработает, он будет синхронизирован с частотой обновления монитора.

person Community    schedule 09.01.2014
comment
Хорошо, можем ли мы считать rAF «доходом» в цикле приложения, позволяющим обрабатывать цикл событий? - person hawkeye; 09.01.2014
comment
@hawkeye yield приостановит целевой поток, который становится немного другим, поскольку только один из rAF и main может выполняться в любой момент времени. Если rAF занят, main не может выполняться, и наоборот. Единственное отличие состоит в том, что rAF может синхронизироваться на низком уровне (с помощью высокоточного таймера и с помощью аппаратного обеспечения), но в остальном он делает то же самое, что, например, setTimeout (своего рода вхождение в очередь). Но необходима некоторая тактика грубой силы по отношению к обычной очереди событий, чтобы обеспечить ее своевременное выполнение. - person ; 09.01.2014
comment
как дела @hawkeye, все в порядке? Мы потратили некоторое время, отвечая на ваш вопрос, это также поможет будущим посетителям. По какой-то конкретной причине вы хотите удалить вопрос? Почему бы не откатиться назад и посмотреть, можно ли улучшить текст? Дайте мне знать.. - person ; 10.01.2014