Sun 14 Dec 2008
Dojo.reload Reloaded: reload app without reloading browser
Posted by liucougar under dojo[9] Comments
After introducing dojo.reload in my previous post, I talked with kriszyp in IRC, and he asked whether dojo.reload can actually modify already created objects from dojo.declare-d classes: in most web 2.0 apps, after the app is loaded, there are lots of instances of classes already created, and using dojo.reload to reload their definition won’t actually update any of these existing instances.
As I do not have an idea to actually implement that, I do come up with another “workaround” (if you like): rather than propagate changes to existing objects on the page, we can actually try to ask the app to reload itself without reloading the whole page. We don’t want to add in any special code in any frontend apps to handle this sort of “self reload” mechanism just to speed up development. Instead, a generic way should be available without any extra logic support in the application layer.
With the help of dojo and with one assumption, I did come up such an implementation to support that. The one assumption is that, all existing objects you care about in your applications are all dijits. If this assumption can be met, what we really need to do in order to reload an application is to:
- call onunload handlers (in case any are registered with dojo)
- destroy all dijits in the page
- reset the
document.body.innerHTMLto what it looks like when the page is first loaded (before any js actually modifys it) - call all onload hanlders registered with dojo (such as dojo.parser etc.)
Item 3 can be achieved via a xhr call to retrieve current page from server and figure out the content within <body> tag. Item 4 requires a bit of extra work, because once all the onload handlers are called by dojo, they are removed. So in order to actually rerun them, we have to remember the original list of handlers.
Of course, as you may already figured, the method mentioned above won’t be able to run any modified onload handlers (even after they are dojo.reload-ed), however, it does cover most of other cases.
The one assumption mentioned above is not actually true in most web 2.0 applications using dojo, in such cases, any non-dijit objects have to be destroyed somehow so that they can be recreated, but that logic has to be application specific. On the other hand, in order to prevent memory leaks in browsers (espcially IE), it is always a good idea to have a destroy function for your objects to clean itself up. So if you are not worried about any thing other than dijits, then the method mentioned above should work reasonably well, while if you do want to re-create other non-dijits stuffs, you can call some application specific cleanup routines (which as I mentioned above would be good to have in any case).
You can find the code in dojoc.util.loader, the function is actually called dojo.reloadPage(). The normal use case for this is:
dojo.reloadany modules you modified and want to test;dojo.reloadPageto actually test them without waiting for reloading all js files/reloading your browser window.
Note: dojo.reloadPage only works if it is included in the initial page load, if you dojo.require dojoc.util.loader after the page is loaded, dojo.reloadPage won’t work (see comment at the beginning of the file to know why)
dojo.reload now also resides in dojoc.util.loader, and compared to the previous version, two additional features are add:
- Partial module name match: now you just need to type in a partial name of the module you want to reload, if it only matches one module already loaded, that module will be reloaded. If there are multiple matches, it will list all possible modules and error out.
- Automatically remove cache of dijit template: if a module references widget template files (using templatePath), these cached templates will be cleared automatically, so next time you create such a dijit, the new template will be loaded from your sever directly.
A new function to reload css files is also included in dojoc.util.loader, dojo.reloadCss, which also supports partial name match. If it is given no argument, it will reload all css files in the page (with a href attribute, of course), similar to ReCSS feature in the firebug lite shipped with dojo core.
Warning: use at your own risk.
RSS feed for comments on this post. TrackBack this post
December 14th, 2008 at 9:23 pm
Just an idea, not sure that it would work, but if you are reloading a dijit widget, why won’t you use dijit.registry to get the list of widgets that are of the type of the widget that you reloaded and mixin to all of them the object you’ve loaded (or search in their inheritance tree for the object you’ve loaded and if it is there then mixin it)
December 14th, 2008 at 9:52 pm
Yes, that will destroy all dijits of a particular type (or its subclasses), but the problem is that, when a dijit (say contentpane) is assigned to a member variable of another dijit (say a bordercontainer), and only contentpane is destroyed, the bordercontainer will still try to access the contentpane dijit using its cache pointer, which will definitely lead to error.
December 14th, 2008 at 11:51 pm
in this case maybe just mixin all the functions, because usually the code that you change is in a logic of a function, and not a value of a non-function member. Moreover, you are not destroying your widgets in this way, you just reassign new logic to the functions (JavaScript`s feature of function are data is just brilliant).
December 15th, 2008 at 10:15 pm
so you are saying mixin all functions to all dijits on the page? I think it may be easier/faster to just destroy them and recreate them
December 16th, 2008 at 11:42 am
I’m saying to mixin for all the relevant objects (the ones that you’ve reloaded) only the function, in this way you’ll gain the new functionallity (that most likely you’ve written within a function) but not loose the current state’s data (which is most likely in the members / data structures of the objects)
December 16th, 2008 at 12:21 pm
ah, I see. Yeah, that should work for simple case (where you have no subclass). However, for more real world cases, such as dijits, inheritage/subclass/mixins are heavily used, I don’t know whether that will work.
In addition, sometimes you change a dijits internal structure or something, then you definitely want to delete the dijit and recreate it.
December 16th, 2008 at 2:25 pm
well, I rarely change code within dijits, only in my classes, still, you can change a code when a subclassing is used, as long as you change the code of a class which is along the line of the superclass pointers ,and you need to check when you reload this path for each widget, or at least once for each class
December 16th, 2008 at 2:51 pm
are you saying you don’t have any custom made widgets? (by dijits, I actually refer to any widgets)
it should work (need to patch each and every existing objects and go through there superclass chain), but I think that’s quite some work
December 19th, 2008 at 10:51 pm
sorry, server is relocated, so some comments were lost