Re: Out of order JS file execution in WebKit

Tristan Seligmann <[email protected]> Thu, 15 Apr 2010 10:45:12 +0200
Newsgroups gmane.comp.python.quotient.dev
Message-ID <[email protected]>
On Thu, Apr 15, 2010 at 8:10 AM, Werner Thie <[email protected]> wrote:
> Tristan, can you give me a pointer for attacking this problem, I like

Hmm, let's see. In order to serialise a widget for dynamic
instantiation, LIveElement._structured() is called. This, in turn,
flattens the element to get the markup; it also uses context.call to
set up lists, including 'requiredModules', which the liveElement
renderer mutates during the course of rendering. This allows it to
collect a list of all modules required by the widget and any of its
children. The list of dependencies is constructed by calling
allDependencies() on the relevant module, and then filtering it with
LivePage._shouldInclude(). _shouldInclude keeps a list of all modules
it has ever been called with, and returns False if one of those
modules is passed in, otherwise True (and adds it to the list); thus,
each module will only be imported once.

For static instantiation, this is exactly what we want, as modules
will be loaded in the correct order, and only once; I'm not sure what
the best way to fix this for dynamic instantiation is. One way to do
it would be to force the client-side code to load modules serially;
this would ensure that they're loaded in the correct order, but this
may affect network performance adversely. I think a better solution
would actually be something similar to what was already discussed in
this thread; although, most of the pieces are already in place.

Scripts are loaded in
Nevow.Athena.Widget._addChildWidgetFromComponents, using
Divmod.Runtime.theRuntime.loadScript(). The implementation differs
between runtimes, but in all cases, it returns a Deferred that only
fires once the module has actually been loaded. This is used to delay
the actual instantiation of the widget until the dependent modules
have been loaded. My suggestion would involve adding a loadScript()
method on the page widget: the first time it's called, it would fire
off the real loadScript() call; if called while the script is still
being loaded, it would return another deferred that fires when the
script has loaded; if called after the script has loaded, it would
return a deferred that fires immediately. The server-side code would
be changed to not filter the dependencies list through _shouldInclude
in the dynamic instantiation case (by adding a flag parameter to the
involved methods, I guess?), so that loadScript() would be called for
all of the dependencies, not just the ones that have never been
loaded. The page setup code would probably need to pass a list of
statically loaded modules to the page widget, so that it knows that
they're already loaded.

Hope that helps; I wrote this based on a cursory reexamination of the
code in question, along with vague recollections from the last time I
looked at the code, so I may have some of the details wrong, but
hopefully this is enough to point you in the right direction.
-- 
mithrandi, i Ainil en-Balandor, a faer Ambar