我遇到多个setTimeout()调用(典型长度:100ms到1秒)处于活动状态且应该已关闭的情况,但它们不会触发。 Chrome(Mac)调试程序配置文件显示"空闲"在这个(可能是无限的)时期。该配置文件显示没有任何进展。没有循环。没有代码在运行。没有垃圾收集。没有任何活动。视口处于活动状态并具有焦点。在我等待(可能是无限时间)之后,当我做其他事情时,像鼠标悬停一些不相关的元素 - 就像a:hover一样简单 - logjam中断,排队的setTimeout()全部触发。
当我在setTimeout()处理函数中设置断点之后"冻结"发生这种情况时,就像你期望的那样,当logjam中断时,它们会按顺序被击中。
不幸的是复制路径很难。到目前为止,创建更简单的测试用例只会使复制变得更加困难,或者最终变得不可能。
大多数围绕setTimeout()"问题"来自那些不了解jscript等单线程特性的人,所以没有用。让我再说一遍:计时器排队等候应该解雇。浏览器处于空闲状态,如分析器所证实。定时器最终会触发,但只有在鼠标活动发生后才会触发。这种行为对我来说似乎非常错误。如果浏览器处于空闲状态,并且队列中有事件,则应触发它们。
有没有人见过这样的行为?我偶然发现了锁定事件调度员的方法吗?也许我错过了一些东西 - 谢谢。
更新:无法在Windows 7上复制。
更新2:在Mac上重新启动Chrome,无法再复制。所以,最糟糕的结果是:没有回答它为什么会发生,为什么它一直在发生,它为什么没有可靠地发生,它为什么会消失,为什么它不再发生。
答案 0 :(得分:0)
我最近遇到了一个类似的问题,发现自47版以来,当他们认为这对大多数用户不利时,铬人决定不尊重setTimeout。基本上他们已经弃用了setTimeout API(像往常一样不问任何人) 以下是人们bug 570845发现的事情。关于这个问题,还有许多其他错误和讨论主题。
后备是使用requestAnimationFrame模拟setTimeout 这是一个概念证明:
'use strict'
var PosfScheduler = ( function () {
/*
* Constructor.
* Initiate the collection of timers and start the poller.
*/
function PosfScheduler () {
this.timers = {};
this.counter = 0;
this.poll = function () {
var scheduler = this;
var timers = scheduler.timers;
var now = Date.now();
for ( var timerId in timers ) {
var timer = timers[timerId];
if ( now - timer.submitDate >= timer.delay ) {
if ( timer.permanent === true ) {
timer.submitDate = now;
} else {
delete timers[timer.id];
}
timer.func.apply.bind( timer.func, timer.funcobj, timer.funcargs ).apply();
}
}
requestAnimationFrame( scheduler.poll.bind(scheduler) );
};
this.poll();
};
/*
* Adding a timer.
* A timer can be
* - an interval (arg[0]: true) - a recurrent timeout
* - a simple timeout (arg[0]: false)
*/
PosfScheduler.prototype.addTimer = function () {
var id = this.counter++;
var permanent = arguments[0] ;
var func = arguments[1] ;
var delay = arguments[2] ;
var funcobj = arguments[3] ;
var funcargs = Array.prototype.slice.call(arguments).slice(4);
var submitDate = Date.now() ;
var timer = {
id: id,
permanent: permanent,
func: func,
delay: delay,
funcargs: funcargs,
submitDate: submitDate,
}
this.timers[id] = timer;
return timer;
};
/*
* Replacement for setTimeout
* Similar signature:
* setTimeout ( function, delay [obj,arg1...] )
*/
PosfScheduler.prototype.setTimeout = function () {
var args = Array.prototype.slice.call(arguments);
return this.addTimer.apply.bind( this.addTimer, this, [false].concat(args) ).apply();
};
/*
* Replacement for setInterval - Untested for now.
* Signature:
* setInterval ( function, delay [obj,arg1...] )
*/
PosfScheduler.prototype.setInterval = function () {
var args = Array.prototype.slice.call(arguments);
return this.addTimer.apply.bind( this.addTimer, this, [true].concat(args) ).apply();
};
PosfScheduler.prototype.cancelTimeout = function ( timer ) {
delete this.timers[timer.id];
};
/*
* Don't want to leave all these schedulers hogging the javascript thread.
*/
PosfScheduler.prototype.shutdown = function () {
delete this;
};
return PosfScheduler;
})();
var scheduler = new PosfScheduler();
var initTime = Date.now();
var timer1 = scheduler.setTimeout ( function ( init ) {
console.log ('executing function1 (should appear) after ' + String ( Date.now() - init ) + 'ms!' );
}, 200, null, initTime );
var timer2 = scheduler.setTimeout ( function ( init ) {
console.log ('executing function2 afte: ' + String ( Date.now() - init ) + 'ms!' );
}, 300, null, initTime );
var timer3 = scheduler.setTimeout ( function ( init ) {
console.log ('executing function3 (should not appear) after ' + String ( Date.now() - init ) + 'ms!' );
}, 1000, null, initTime );
var timer4 = scheduler.setTimeout ( function ( init, sched, timer ) {
console.log ('cancelling timer3 after ' + String ( Date.now() - init ) + 'ms!' );
sched.cancelTimeout ( timer3 );
}, 500, null, initTime, scheduler, timer3 );
var timer5 = scheduler.setInterval ( function ( init, sched, timer ) {
console.log ('periodic after ' + String ( Date.now() - init ) + 'ms!' );
}, 400, null, initTime, scheduler, timer3 );
var timer6 = scheduler.setTimeout ( function ( init, sched, timer ) {
console.log ('cancelling periodic after ' + String ( Date.now() - init ) + 'ms!' );
sched.cancelTimeout ( timer5 );
}, 900, null, initTime, scheduler, timer5 );