Issue metadata
Sign in to add a comment
|
`transitionend` not sent after CSS transition
Reported by
jando...@gmail.com,
Dec 1 2017
|
||||||||||||||||||||||
Issue descriptionUserAgent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_1) AppleWebKit/604.3.5 (KHTML, like Gecko) Version/11.0.1 Safari/604.3.5 Steps to reproduce the problem: 1. Load the app What is the expected behavior? After dissolve of the preloader, the page gets updated further What went wrong? Visualization of the page freezes completely, while the other code continues normally. An expected `transitionend` was not sent. Did this work before? Yes Chrome 57 Does this work in other browsers? Yes Chrome version: Version 62.0.3202.94 (Official Build) (64-bit) Channel: stable OS Version: OS X 10.13.1 Flash Version: Since Chrome v58, some Chrome process [sometimes (Mac) | very often (Win)] goes haywire around a CSS transform transition. It now seems plausible that this is a bug in Chrome, and not in our code. I did not find any reference to this behavior in the known issues or on the web in general. The closest is [Some CSS transitionend events don't fire on Android devices without displays](https://bugs.chromium.org/p/chromium/issues/detail?id=781924). The problem seems to go away when the CSS transform is removed. It looks like some Chrome process (the render engine?) stops, or stops communicating, with the net effect that Chrome stops updating the visualization of a page, while other parts, e.g., JavaScript, XHR, … keep working as expected. The issue occurs in a private business application, during setup. To demonstrate the problem, I created 2 screencasts, one for Mac, and one for Windows, that show first a normal load, then several reloads, until the issue occurs. In the screencasts the developer tools are used to inspect some properties. Finally, after several minutes, Chrome shows a message. During the screencast, you'll see me record a heap snapshot and timeline. These are attached. - Mac: [https://youtu.be/DVxRp6h4OAQ] - Windows: [https://youtu.be/y7DcZ-DelcE] Context ------- The issue occurs at least in 2 different SPAs, that share common code. I will discuss the simplest one. These SPAs are built with dojo, dijit, dojox, util, currently at version 1.13.0; put-selector 0.3.6; xstyle 0.3.2; the simple SPA discussed here uses dgrid 0.3.19. The debugging effort, and evolution of the code since the issue surfaced, makes it unlikely that the issue is related to these libraries. This is a large application, that contains complex JavaScript code, and shows it's age. It is not impossible that our code has issues, but even then, the behavior of Chrome is not what it should be. Our code ends nominally, continuing long after the issue occurs. The issue immediately occurred when Chrome 58 was released, and can be reproduced on Win and Mac, although much more easily on Win than Mac. This issue does not occur on Firefox, Safari, or Edge, on Win nor Mac. On Windows, the issue occurs so often that using Chrome has become impossible for the users. Description of the issue ------------------------ ### Normal behavior The screencasts first show me loading the SPA with normal results. The SPA starts out with a preloader. Debugging shows this is where the issue is. Behind the preloader, dojo parses its templates, and populates the DOM. When the layout is ready, the preloader is removed, and we see the SPA layout (Mac: 00:13, Win: 00:16 in the screencast). There does not seem to be an issue with this. The SPA is split in a left and a right side. For the purposes of this issue, the right hand side is inert. On the left hand side, we see a list with paging. When the preloader dissolves, an XHR is already busy getting information from the server for the first page. Deserialization of this data is rather involved, and uses a queuing mechanism to leave CPU time for user interaction. The console shows log information about the deserialization process. During initial load, we see a loading message in the left hand pane, and a turning busy indicator. The busy indicator is an animated gif, attached via CSS. At the bottom, there is a slim blue progress indicator, that shows the depth of the queue. When the data for the first page is deserialized, it is handed to the list, and rendered. The loading message and busy indicator are replaced with the list entries for the first page (Mac: 00:15, Win: 00:18). In the console you can see that logging continues: the lists preloads a second page after the first page is rendered. The bottom slim blue progress indicator jumps up a second time. This goes on for some seconds. After that, all JavaScript is done, and the SPA is waiting for user input (Mac: 00:19, Win: 00:24). In the screencast, you see me opening the Elements inspector, and drilling down in the DOM to show the elements of the first item of the list (Mac: 00:37, Win: 00:48). These were added by the JavaScript code after the page got loaded. Also note that we see rectangles in the Chrome window that show which elements I am hovering over with my mouse in the Elements inspector. Note that The first element in the body is <div id="fixedSplitter" … Notably, there is no `<div id="preloader" …` in the body at this time. The preloader originally is <div id="preloader"><div class="progress"><div></div></div></div> with CSS [https://github.com/peopleware/js-ppwcode-util-oddsAndEnds/blob/fe7ff76108fc4a1ce463a317f05009de2694258f/preloader/preloader.css]. The css makes the div page filling, and on top, with a CSS loading indicator. Transitions are setup for dissolving the preloader when the page is loaded. Dissolving happens by adding CSS class "dissolved" to the "preloader" div. #preloader { […] transition: all 0.75s linear; } #preloader.dissolved { opacity: 0; transform: skewx(90deg) rotate(-90deg); } […] #preloader.dissolved .progress { display: none; } The code listens to "transitionend" to finally remove the `preloader` div and its contents from the DOM. function dissolvePreloader(/*String*/ preloaderId) { var deferred = new Deferred(); var preloader = dom.byId(preloaderId); var spinner = query(".progress", preloader)[0]; preloader.addEventListener( "transitionend", function() { domConstruct.destroy("preloader"); deferred.resolve(preloaderId); }, true ); domClass.add(preloader, "dissolved"); return deferred.promise; } Debugging shows the listener is activated 3 times, for font-size, opacity, and transform. (In hindsight, this is not optimal code, but it is the code currently that shows the issue, which occurs before the listener is triggered.) ### Getting the issue to occur Next in the screencast, you will see me reloading the page several times, trying to get the issue to occur. I do not always wait for the page to load completely. As soon as I can see that the issue isn't occurring, I try again. And sometimes I don't even wait that long, based on the feeling that 'taxing' the browser more heavily will force the issue quicker. There is no scientific evidence for that, there are even more hints to the opposite, so that is purely emotional. On Mac, it takes about 10 minutes of continuously reloading for the issue to occur. I've edited most attempts out of the screencast. On Windows, it only takes a couple of tries. The issue occurs on 01:26 in the Mac screencast, and on 01:43 in the Windows screencast. ### Behavior when the issue occurs The SPA starts out with the preloader, and parses and renders the layout behind it, as with the normal behavior. The preloader dissolves as expected (Mac: 01:25, Win: 01:42). We see the layout, with the inert right hand side, and the list at the left, showing the loading message and the animated gif busy indicator. THE ANIMATED GIF IS NOT TURNING. **From this time on, the contents of the Chrome tab is completely frozen.** In the console we can see that the JavaScript continues normally. We see the initial log messages, the deserialization of the first page, and, seconds after the preloader dissolved, the start of the second page load and its deserialization, up to completion as with the normal runs (Mac: 01:31, Win: 01:52). **The visual representation however did not change after the preloader dissolved.** _In the mean time, the ventilators in my computer have started._ In this phase, nothing seems to be going on in the SPA, yet we see a rather high CPU usage of Chrome (and the Chrome DevTools). I now have some minutes to do some inspections. In the screencast you see me opening the Elements inspector, and drilling down in the DOM to show the elements of the first item of the list. **THE DOM IS FILLED OUT (except for the preloader, see below), YET IT IS NOT SHOWN IN THE CHROME WINDOW.** Also note that no rectangles are shown in the Chrome window as I hover over elements in the Elements inspector. (Mac: 02:05, Win: 02:18) The first element in the body is `<div id="preloader" …`. The second is `<div id="fixedSplitter" …`. When I do a recording in the Performance tab, we see that no code is active, apart from some GPU blibs. The heap snapshot and timeline you see me make are attached. **Debugging shows that the PRELOADER EVENT LISTENER IS _NEVER_ CALLED, although clearly THE TRANSITION WAS EXECUTED**. The preloader visual is gone, it did so with the transitions (see screencast), and the style of the preloader div is "dissolved" afterwards, yet it is not removed from the DOM. **For some reason, the process doing the CSS transition never sent the `transitionend` event.** ### The aftermath After several minutes waiting for the grand finale, I give up, and start to interact. After several minutes, on Windows, Chrome does come up with an 'Aw, Snap!' and 'Debugging Connection was closed. Reason: Render process gone. […]'. When I close the Chrome Windows, I can start over. (Win: 07:34) On Mac, things are more dire. The wait for a message takes much longer (up to over 15 minutes - most of this is edited), and when it gets there it shows 'Page Unresponsive - You can wait for it to become responsive or exit the page. […]'. (Mac: 06:33) The reason that this takes longer might be that the Macs I work on have a lot of RAM, while the Windows machine has less. In any case, on Mac, the ventilators are doing overtime by now, although this doesn't really show in the CPU load. Over the next minutes, the Mac becomes more and more sluggish. In the recording of this screencast, the end is not shown. At the end, I am desperately trying to kill Chrome, to be able to save the screencast, but that is almost impossible. Over different tries, I observed that the longer I wait, to more difficult it becomes to interact with the machine. My hypothesis here is that it is not CPU, but memory that is at the heart of this effect. Although little seems to be going on, something in Chrome seems to consume more an more RAM, to the point of making the OS trash. I have had one occurence where this experience actually crashed the machine as a whole. ### Workaround We removed the `transform` transition, and made the `transition` slower in the CSS. The issue has not occurred again since the change. [https://github.com/peopleware/js-ppwcode-util-oddsAndEnds/blob/17d7d9e8ae517ba14ba247ffe5bf06d9aca670ec/preloader/preloader.css] #preloader { […] transition: all 2s linear; } #preloader.dissolved { opacity: 0; } ### Hypothesis For some reason, the Chrome rendering process goes into some endless recursion when a transition is executing or done, before `transitionend` can be signalled. It doesn't process changes to the DOM anymore, but keeps slugging on, consuming a small amount of RAM on every turn. Finally, something detects this on Windows, and stops the silliness. On Mac, this detection is less advanced, so things get out of whack further. I have no hypothesis why the issue occurs far more frequent on Win than Mac.
,
Dec 1 2017
,
Dec 1 2017
,
Dec 4 2017
Tried testing the issue on mac 10.12.6 using chrome reported version #62.0.3202.94 by navigating to url: https://test.pictoperfect.com/ui/index.html, but logging into the page require credentials. jandockx@ - Could you please provide sample credentials to test the issue from TE-end. This will help us in triaging the issue further. Thanks...!!
,
Feb 1 2018
Closing due to inactivity and inability to reproduce. |
|||||||||||||||||||||||
►
Sign in to add a comment |
|||||||||||||||||||||||
Comment 1 by jando...@gmail.com
, Dec 1 2017