为什么事件处理程序要等到触发代码执行完毕?

Why does event handler wait until triggering code completes execution?

以下片段说明了我的问题。我有一些代码为 customeventstart 事件调用 jQuery.trigger,然后进行一些密集处理,然后它再次为 customeventstop 事件调用 jQuery.trigger

我希望 customeventstart 的事件处理程序立即执行。但是,在控制台显示 customeventstart 处理程序的结果之前存在明显的延迟。似乎在触发代码执行完毕后才调用事件处理程序。

注意:您可以根据机器的处理能力将代码片段中的循环迭代次数调整为 lengthen/shorten 延迟。

btn = $('#btn');

btn.on('click', function() {
  btn.trigger('customeventstart');
  
  // intensive/time-consuming processing
  for (var i = 0; i < 100000000; ++i) {
    'string' + 'concatenation'; 
  }
  console.log('intensive processing done');
  
  btn.trigger('customeventstop');
});

btn.on('customeventstart', function() {
  console.log('starting');
});

btn.on('customeventstop', function() {
  console.log('stopping');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">This may take a while</button>

我打算使用异步 Web Workers 解决方案,但我想更好地了解发生了什么。

为什么 jQuery.triggered 事件的处理程序等待或似乎等待触发代码完成?

我认为这与 Firefox(和 Firebug)中的 console.log 实施有关,而不是事件的实际时间。

我尝试对您的代码片段进行以下修改,基本上只是添加 Date.now 和更多的控制台日志语句:

btn = $('#btn');

btn.on('click', function() {
  console.log(Date.now() + ': triggering customeventstart');
  btn.trigger('customeventstart');
  
  // intensive/time-consuming processing
  console.log(Date.now() + ': starting intensive processing');
  for (var i = 0; i < 100000000; ++i) {
    'string' + 'concatenation'; 
  }
  console.log(Date.now() + ': intensive processing done');
  
  console.log(Date.now() + ': triggering customeventstop');
  btn.trigger('customeventstop');
});

btn.on('customeventstart', function() {
  console.log(Date.now() + ': starting');
});

btn.on('customeventstop', function() {
  console.log(Date.now() + ': stopping');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">This may take a while</button>

对我来说:

  • 在 Chrome 和 IE11 上,单击按钮会导致前三个日志语句(通过 "starting intensive processing")的近乎即时的记录,然后是延迟,然后是其余的行。顺序和时间由线上的时间戳证实。

  • 在 Firefox 上,单击按钮会导致延迟,然后所有行一起出现 — 但如果您查看时间戳,很明显延迟实际上发生在 "starting intensive processing" 之间和 "intensive processing done" 与 Chrome 和 IE11 一样的日志语句(我必须在循环最大值中添加一个 0 才能在 Firefox 中看到这一点——哇,这些天这些东西很快):

"1424713006530: triggering customeventstart"
"1424713006530: starting"
"1424713006531: starting intensive processing"
"1424713007263: intensive processing done"
"1424713007263: triggering customeventstop"
"1424713007264: stopping"

所以并不是事件在延迟后被触发,而是如果主 UI 线程繁忙,Firefox 的 console.log 实现似乎会被暂停。

这与主 UI 线程繁忙时浏览器可能不会更新页面显示的常见情况非常相似。例如,在下面的代码片段中,我们在进行密集处理时将按钮的背景变为红色(根本不使用任何自定义事件),然后在完成后恢复它;但是在大多数浏览器上,即使在处理过程中有足够的时间,您也根本看不到按钮的背景发生变化:

btn = $('#btn');

btn.on('click', function() {
  console.log(Date.now() + ': turning button background red');
  btn.css('background-color', 'red');
  
  // intensive/time-consuming processing
  console.log(Date.now() + ': starting intensive processing');
  for (var i = 0; i < 100000000; ++i) {
    'string' + 'concatenation'; 
  }
  console.log(Date.now() + ': intensive processing done');
  
  console.log(Date.now() + ': restoring button background');
  btn.css('background-color', '');
});
(Look in the console.)
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="btn">This may take a while</button>