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

时间:2015-02-23 16:44:30

标签: javascript jquery events jquery-events

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

我希望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');
});
&#13;
<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>
&#13;
&#13;
&#13;

我打算使用异步Web Workers解决方案,但我想更好地了解正在发生的事情。

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

1 个答案:

答案 0 :(得分:0)

我认为这与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上,单击按钮会导致延迟,然后所有行都会一起显示 - 但是如果查看时间戳,很明显延迟实际发生在“开始密集处理”和“密集处理”之间完成“与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>