簡體   English   中英

卡住 setTimeout()s (Chrome)

[英]Stuck setTimeout()s (Chrome)

我遇到了多個setTimeout()調用(典型長度:100 毫秒到 1 秒)處於活動狀態並且應該關閉的情況,但它們沒有觸發。 Chrome (Mac) 調試器配置文件在此(可能無限)期間顯示“空閑”。 配置文件顯示沒有任何事情發生。 沒有循環。 沒有代碼運行。 沒有垃圾收集。 沒有任何活動。 視口處於活動狀態並具有焦點。 在我等待(可能是無限的時間)之后,當我“做其他事情”時,比如將mouseover一些不相​​關的元素上——就像 :hover 一樣簡單——僵局打破了,排隊的setTimeout()都被觸發了。

當我在“凍結”發生后在setTimeout()處理函數中設置斷點時,它們會在卡頓中斷時按順序命中,正如您所期望的那樣。

不幸的是,復制路徑很困難。 到目前為止,創建更簡單的測試用例只會讓復制變得更加困難,或者最終是不可能的。

大多數圍繞setTimeout() “問題”的喋喋不休來自不了解 jscript 等單線程性質的人,所以它沒有幫助。 讓我再說一遍:計時器已排隊,應該已觸發。 正如分析器所證明的那樣,瀏覽器處於空閑狀態。 計時器最終會觸發,但僅在鼠標活動發生后觸發。 這種行為對我來說似乎非常錯誤。 如果瀏覽器空閑,並且隊列中有事件,它們應該被觸發。

有沒有人見過這樣的行為? 我是否偶然發現了一種鎖定事件調度程序的方法? 也許我錯過了一些東西。

更新:無法在 Windows 7 上復制。

更新 2:在 Mac 上重新啟動 Chrome,無法再復制。 所以,最糟糕的可能結果:沒有回答為什么會發生,為什么會一直發生,為什么它沒有可靠地發生,為什么它消失了,為什么它不會再發生了。

我最近遇到了類似的問題,並發現自 47 版以來,鉻人決定不尊重 setTimeout,因為他們認為這“對大多數用戶有害”。 基本上他們已經棄用了 setTimeout API(像往常一樣不問任何人)。
這是人們發現的錯誤 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 );

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM