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

Why does event handler wait until triggering code completes execution?

本文关键字:代码 执行 事件处理 程序 为什么      更新时间:2024-03-22

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

我期望customeventstart的事件处理程序立即执行。但是,在控制台显示customeventstart处理程序的结果之前有一个明显的延迟。事件处理程序似乎直到触发代码完成执行后才会被调用。

注意:您可以根据机器的处理能力调整代码段中循环的迭代次数,以延长/缩短延迟。

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上,点击按钮会导致前三条日志语句几乎即时记录(通过"开始密集处理"),然后是延迟,然后是其余行。线路上的时间戳证明了顺序和时间。

  • 在Firefox上,单击该按钮会导致延迟,然后所有行一起出现—但如果你看一下时间戳,很明显,延迟实际上发生在"开始密集处理"answers"完成密集处理"日志语句之间,就像Chrome和IE11一样(我不得不在循环最大值上加一个0才能在Firefox中看到这一点—哇,现在这些事情很快):

"1424713006530:触发customeventstart"1424713006530:正在启动"1424713006531:开始密集处理"1424713007263:已完成密集处理"1424713007263:触发customeventstop"1424713007264:正在停止"

因此,这并不是说事件在延迟后被触发,而是如果主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>