Javascript Event Queuing: XHR-ответ в размытии ставится в очередь перед родительским щелчком - PullRequest
0 голосов
/ 31 октября 2018

Для следующего контрольного примера (я заменил вызов XHR на setTimeout для представления вызова XHR с очень быстрым ответом):

<html>
  <body>
     <div onclick="console.log('onclick parent')">
       Event Queue Test:
       <input type=text onblur="console.log('onblur'); setTimeout(function() {console.log('onblur timeout')})"/>
     </div>
   </body>
</html>

Если щелкнуть текстовое поле, а затем щелкнуть текст, предшествующий текстовому полю, я получу следующий вывод в Chrome (v70):

onblur
onblur timeout
onclick parent

Я бы ожидал, что родительский обработчик onclick будет поставлен в очередь до события setTimeout. В Chrome, по крайней мере, этого нет. Это поведение определяется стандартом или зависит от реализации? Меня также интересуют обходные пути, позволяющие всегда запускать родительский обработчик onclick перед обработчиком тайм-аута (или XHR).

В моем реальном случае использования эта проблема проблематична, поскольку не гарантируется, что события будут поставлены в очередь в одном и том же порядке, в зависимости от того, сколько времени требуется для выполнения запроса XHR.

1 Ответ

0 голосов
/ 31 октября 2018

Это не обязательно поможет с вашей реальной проблемой XHR, но я думаю, что понимаю, что происходит. Я расширил ваш пример кода, используя для удобства jQuery:

<div class=parent>Label: <input class=field></div>

и JavaScript:

var $d = $(document);

var t = {
  mousedown: -1,
  mouseup: -1,
  focus: -1,
  click: -1,
  blur: -1,
  timer: -1
};

["mousedown", "mouseup", "focus", "click"].forEach(function(event) {
    $d.on(event, ".parent", function() {
    t[event] = Date.now();
  })
});
$d.on("blur", ".field", function() {
    t.blur = Date.now();
  setTimeout(function() {
    t.timer = Date.now();
  }, 150);
});
$d.on("click", ".parent", function() {
    setTimeout(function() {
    var race = Object.keys(t).sort(function(k1, k2) { return t[k1] - t[k2];});
    console.log("Result: ", race);
    race.forEach(function(key) { t[key] = -1; });
  }, 1000);
});

Что делает этот код, так это упорядочивает события по времени, когда они действительно происходят. В случае щелчка по тексту после щелчка и фокусировки в поле ввода, порядок с коротким тайм-аутом (менее 100 мс или около того) составляет

  1. внимание
  2. MouseDown
  3. Размытие
  4. Таймер
  5. MouseUp
  6. нажмите

События «размытия» и «таймера» предназначены для поля ввода и его обратного вызова setTimeout(). Если я увеличу интервал ожидания, например, 150 мс или около того, я получу

  1. внимание
  2. MouseDown
  3. Размытие
  4. MouseUp
  5. нажмите
  6. Таймер

Это, я думаю, имеет некоторый смысл: события "mousedown" и "mouseup" обусловлены вашим фактическим физическим взаимодействием с кнопкой мыши. Событие «click» не имеет смысла, пока не будет получено «mouseup». С коротким таймером в обработчике «размытия» таймер может сработать до того, как мышь физически сообщит о событии «вверх» через вашу ОС и т. Д.

...