Opened 8 years ago

Closed 8 years ago

Last modified 8 years ago

#14277 closed defect (fixed)

ScrollableView throws unbounded errors when destroyed quickly after startup.

Reported by: brianrcody Owned by: ykami
Priority: high Milestone: 1.7.1
Component: DojoX Mobile Version: 1.6.1
Keywords: Cc:
Blocked By: Blocking:

Description

If a ScrollableView? is destroyed quickly after being started up, it will throw an unbounded number of errors of the form "Cannot read 'style' property of null". It appears that calling startup() on a ScrollableView? sets up an interval that needs to run five times before it is cleared. During the processing of that interval, it is expected that the DOM node for the ScrollableView? is still alive. There is no check for its existence. So if the node has been destroyed, then an error is thrown (on line 192 of srollable.js), and worse, the interval is never cleared, so it will try again and again, throwing errors ad nauseam.

I have attached a simple HTML page that displays this problem. Simply click on the link quickly after the page loads, then be on the lookout in the console for errors.

Attachments (1)

bug.html (1.4 KB) - added by brianrcody 8 years ago.
Simple manifestation of the bug.

Download all attachments as: .zip

Change History (6)

Changed 8 years ago by brianrcody

Attachment: bug.html added

Simple manifestation of the bug.

comment:1 Changed 8 years ago by ykami

It is not going to be easy to support such a usage as we are adding asynchronous, lazy processing more and more in 1.7 or later. Even in this particular case, I don't think simply adding a check code in the setInterval is enough. But I think you can easily avoid it yourself by delaying the destruction.
Just out of curiosity, in what use cases do you need to destroy a view widget immediately after its creation?

comment:2 Changed 8 years ago by brianrcody

I may not be using the views as intended, but this is what I'm doing. I have a little photo viewer app that can be in one of three states: view albums (a single ScrollableView?), view photo thumbnails within an album (another single ScrollableView?), and view photos in an album (a set of FlippableViews?). When the user moves from one state to another (say, by selecting an album or photo), I destroy all of the existing widgets and create new ones for the new state. Admittedly, I am new to Dojo, so the destruction of the widgets was motivated by the fact that I was having trouble getting the FlippableViews? to play nicely next to a ScrollableView?. In any event, given this setup, it is quite possible that a user may select one album, then quickly (within 1.5s) hit the back button, which would destroy the ScrollableView?.

I certainly understand the desire to do more work asynchronously. However, it does seem strange that a view should provide a destroy API but have implicit limitations on when it can be called. In this case, I needed to dig into the source code to see what was going on, and putting a delay in my code betrays a leaky abstraction. I think that any new lazy processing should be robust against widget deletion. Otherwise, users would need to develop an understanding of all of the different pieces of delayed processing and how they affect their ability to control the widget's lifecycle. Given that each bit of delayed processing could have its own timeouts and its own logic, I feel that this is an undue burden on the user.

comment:3 Changed 8 years ago by ykami

Milestone: 1.8

Thank you for the explanation. That sounds reasonable. Let me consider this in 1.8.

comment:4 Changed 8 years ago by ykami

Resolution: fixed
Status: newclosed

In [27370]:

Fixes #14277, #14435 !strict Checks this.domNode in flashScrollBar(). It may not be available if the widget is destroyed immediately after its creation.

comment:5 Changed 8 years ago by ykami

Milestone: 1.81.7.1

In [27369]:

Fixes #14277, #14435 !strict Checks this.domNode in flashScrollBar(). It may not be available if the widget is destroyed immediately after its creation.

Note: See TracTickets for help on using tickets.