У меня есть блок кода 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
, даже когда постоянно перемещаю мышь в поле. Не уверен, что там происходит.)