События ввода DOM и порядок setTimeout / setInterval

У меня на моей странице работает блок кода JavaScript; назовем его func1 . Для запуска требуется несколько миллисекунд. Пока этот код выполняется, пользователь может щелкнуть, переместить мышь, ввести какой-либо ввод с клавиатуры и т. Д. У меня есть еще один блок кода, func2 , который я хочу запустить после всех этих вводимых в очередь вводов. события разрешились. То есть я хочу обеспечить порядок:

  1. func1
  2. Все обработчики, привязанные к входным событиям, которые произошли во время работы func1
  3. func2

Мой вопрос: Is вызов 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: Частичное решение: nest func2 внутри двух тайм-аутов, удаляя все обработчики входных событий в первый тайм-аут. Однако у этого есть неприятный побочный эффект, заключающийся в том, что некоторые или даже все входные события, которые произошли во время func1 , не разрешаются. (Зайдите на http: // jsfiddle.net / EJNSu / 10 / и попробуйте быстро щелкнуть ссылку несколько раз, чтобы увидеть это поведение. Сколько кликов сообщает вам предупреждение о том, что вы сделали?) И это снова меня удивляет; Я бы не подумал, что вызов setTimeout func2, 0 , где func2 устанавливает onclick в null , может предотвратить запуск этого обратного вызова в ответ на щелчок, произошедший секунду назад. Я хочу убедиться, что все входные события срабатывают, но моя функция срабатывает после них.

Обновление 3: Я опубликовал свой ответ ниже после игры с этим испытательным стендом, который освещает: http: // jsfiddle .net / TrevorBurnham / uJxQB /

Наведите указатель мыши на поле (запускает 1-секундный цикл блокировки), затем щелкните несколько раз. После цикла все выполненные вами щелчки воспроизводятся: обработчик click верхнего блока переворачивает его под другим блоком, который затем получает следующий щелчок и так далее. Тайм-аут, запускаемый в обратном вызове mouseenter , не всегда происходит после событий щелчка, а время, необходимое для возникновения событий щелчка, сильно различается в разных браузерах даже на одном и том же оборудовании и ОС. (Еще одна странность, обнаруженная в этом эксперименте: я иногда получаю несколько событий jQuery mouseenter , даже когда постоянно перемещаю мышь в поле. Не уверен, что там происходит.)

12
задан Trevor Burnham 24 June 2011 в 16:42
поделиться