У меня есть блок кода JavaScript, который запущен на моей странице; позвоните ему func1
. Выполняется несколько миллисекунд. Пока этот код запущен, пользователь может щелкнуть, переместить мышь, ввести ввод с клавиатуры и т.д. У меня есть еще один блок кода func2
, который я хочу запустить после того, как все эти события, связанные с очередностью ввода, будут разрешены. То есть, я хочу обеспечить порядок:
-
func1
- Все обработчики, связанные с событиями ввода, которые произошли во время
func1
, выполнялись -
func2
Мой вопрос: Является ли вызов setTimeout func2, 0
в конце func1
достаточным для обеспечения этого заказа во всех современных браузерах? Что делать, если эта строка появилась в начале func1
- какой порядок я должен ожидать в этом случае?
Пожалуйста, создайте резервные копии своих ответов либо с ссылками на соответствующие спецификации, либо с помощью тестовых примеров.
Обновление: Оказывается, что нет, этого недостаточно. В моем первоначальном вопросе я не понял, что входные события даже не добавляются в очередь до тех пор, пока не будет выполнен текущий блок кода. Поэтому, если я пишу
// time-consuming loop...
setTimeout func2, 0
то только после этого setTimeout
будет запущен любой входной события (клики и т.д.), которые произошли во время цикла времени. (Чтобы проверить это, обратите внимание, что если вы удаляете, скажем, обратный вызов onclick
сразу после цикла, требующего много времени, то щелчки, которые произошли во время цикла, не будут инициировать этот обратный вызов.) Таким образом, func2
сначала ставится в очередь и принимает старшинство.
Установка тайм-аута 1
, похоже, обошла проблему в Chrome и Safari, но в Firefox я видел, как входные события разрешались после тайм-аутов до 80
(!). Таким образом, чисто основанный на времени подход явно не собирается делать то, что я хочу.
Нет, достаточно просто обернуть один setTimeout ... 0
внутри другого. (Я надеялся, что первый тайм-аут будет срабатывать после ввода событий в очереди, а второй будет срабатывать после того, как они разрешатся. Нет такой удачи.) Также не было добавлено третьего или четвертого уровня вложенности (см. Обновление 2 ниже).
Итак, если у кого-то есть способ достичь того, что я описал (кроме установки тайм-аута в 90+ миллисекунд), я был бы очень благодарен. Или это просто невозможно с текущей моделью событий JavaScript?
Здесь мой последний тестовый стенд JSFiddle: http://jsfiddle.net/EJNSu/7/
Обновление 2: Частичное обходное решение - вложить func2
внутри двух тайм-аутов, удалив все обработчики входных событий в первый тайм-аут. Однако у этого есть неудачный побочный эффект, вызвавший неспособность решить некоторые или даже все входные события, произошедшие во время func1
. (Перейдите в http://jsfiddle.net/EJNSu/10/ и попробуйте быстро нажать ссылку несколько раз, чтобы наблюдать за этим поведением. Сколько кликов предупреждает вас о том, что у вас было? ) Так что это снова меня удивляет; Я бы не подумал, что вызов setTimeout func2, 0
, где func2
устанавливает onclick
в null
, может помешать этому обратному вызову быть запущенным в ответ на щелчок, который произошел полторы секунды назад. Я хочу, чтобы все входные события срабатывали, но моя функция срабатывает после них.
Обновление 3:. Я отправил свой ответ ниже после игры с этим тестом, который освещает: http://jsfiddle.net/TrevorBurnham/uJxQB/
Переместите курсор мыши над полем (запуск 1-секундного цикла блокировки), затем щелкните несколько раз. После цикла все сделанные вами клики выходят: Верхний бокс click
обработчик переворачивает его под другим полем, который затем получает следующий click
и т.д. Тайм-аут, вызванный обратным вызовом mouseenter
, последовательно не возникает после событий кликов, и время, которое требуется для событий кликов, сильно варьируется в браузерах даже на одном оборудовании и ОС. (Еще одна странная вещь, в которой появился этот эксперимент: иногда я получаю несколько событий jQuery mouseenter
, даже когда я постоянно перемещаю курсор мыши в окно. Не уверен, что происходит там.)