Smooth Scroll Causes setTimeout to Behave Erratically
Reported by
jacklu...@gmail.com,
Aug 7 2017
|
|||||
Issue descriptionUserAgent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/60.0.3112.90 Safari/537.36 Steps to reproduce the problem: 1. Go to a major website with a complicated layout (im using cnn.com) 2) Open dev tools and navigate to console 3) Paste the following snippet // this snippet logs time for a setTimeout to fire window.onscroll = function() { if(window.i == undefined) { window.i = 0; } else { window.i++; } var k = i; console.time('timer'+k); setTimeout(function(){ console.timeEnd('timer'+k); }, 50); }; 4) Position mouse over the scroll bar (so to not trigger any dom events) and scroll using your mousewheel 5) Notice that the setTimeout will fire at intervals that can spike many multiples of 100ms. (for me as high as 4000ms) 5) Now try scrolling by left clicking on the scroll bar and dragging it downward 6) Notice that the timer nearly always occurs correctly at 50ms 7) If the issue doesnt occur immediately try leaving the tab stale, minimizing etc, then coming back to the page and trying again What is the expected behavior? setTimeout when scrolling using mousewheel should still execute near 50ms from scroll event. Understandably this can vary, but using mousewheel I've seen it show up as slow as 2000ms for a 50ms timer. Using the same behavior with a mouse dragging the scrollbar does not have issues. Other browsers (tested firefox, ie) appear to reproduce the timer more consistently without large spikes. What went wrong? This issue with setTimeout occurs for all timers on a page after using mousewheel to scroll, for example if there is a setTimeout in the event handler of a page element it may also be delayed. I noticed that setTimeout() i use to debounce dropdowns/popups in semantic-ui (semantic-ui.com) in recent versions of Chrome would appear not to function immediately after using mousewheel to scroll. I then realized this seems to occur on any setTimeout usage immediately after or during scroll specifically with mousewheel. Did this work before? N/A Does this work in other browsers? Yes Chrome version: 60.0.3112.90 Channel: stable OS Version: 10.0 Flash Version: Shockwave Flash 26.0 r0 Example output from nytimes.com timer0: 293.398193359375ms VM274:11 timer1: 277.624267578125ms VM274:11 timer2: 260.62109375ms VM274:11 timer3: 244.38330078125ms VM274:11 timer4: 227.494873046875ms VM274:11 timer5: 211.114990234375ms VM274:11 timer6: 194.045166015625ms VM274:11 timer7: 177.667724609375ms VM274:11 timer8: 161.2470703125ms VM274:11 timer9: 144.19873046875ms VM274:11 timer10: 128.044189453125ms VM274:11 timer11: 111.556884765625ms VM274:11 timer12: 94.134033203125ms VM274:11 timer13: 78.60302734375ms VM274:11 timer14: 61.9140625ms VM274:11 timer15: 52.564208984375ms VM274:11 timer16: 52.06201171875ms VM274:11 timer17: 50.735107421875ms VM274:11 timer18: 53.10498046875ms VM274:11 timer19: 51.208984375ms VM274:11 timer20: 50.52783203125ms VM274:11 timer21: 50.4677734375ms VM274:11 timer22: 50.29296875ms VM274:11 timer23: 269.1669921875ms VM274:11 timer24: 252.72705078125ms VM274:11 timer25: 236.729736328125ms VM274:11 timer26: 220.343994140625ms VM274:11 timer27: 202.99609375ms VM274:11 timer28: 186.555908203125ms VM274:11 timer29: 170.58984375ms VM274:11 timer30: 136.77783203125ms VM274:11 timer31: 121.742919921875ms VM274:11 timer32: 105.121826171875ms VM274:11 timer33: 88.4970703125ms VM274:11 timer34: 72.141845703125ms VM274:11 timer35: 55.921875ms VM274:11 timer36: 50.281005859375ms
,
Aug 7 2017
Correction: the spec-compliant solution in your case would be to use a capturing event listener ("useCapture" parameter should be "true"):
window.addEventListener('scroll', function() { ..... }, true);
,
Aug 8 2017
Unable to reproduce this issue on Windows-10 using chrome latest stable #60.0.3112.90 by following steps mentioned in the original comment, Observed the setTimeout didn't fire more than 70ms while scrolling the CNN page using mouse scroll. Attaching screen-cast for reference could you please take a look in to this issue and let me know if anything is missing fro my end. Thanks!
,
Aug 8 2017
On a page with a potentially blocking wheel event handlers, Chrome may choose to defer timer execution in order to improve animation smoothness. You should see a message about this in the developer console if this is happening in your case. One way to avoid this is to make your event handlers passive[1] so that the browser knows that main thread responsiveness isn't critical to animation smoothness. (IIRC we might still be missing some scheduler plumbing related to handler passiveness so we may need to tweak some things here.) [1] https://github.com/WICG/EventListenerOptions/blob/gh-pages/explainer.md
,
Aug 8
This issue has been Available for over a year. If it's no longer important or seems unlikely to be fixed, please consider closing it out. If it is important, please re-triage the issue. Sorry for the inconvenience if the bug really should have been left as Available. For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
,
Aug 9
|
|||||
►
Sign in to add a comment |
|||||
Comment 1 by woxxom@gmail.com
, Aug 7 2017