Is there a reason why we just don't add Runnable and Callable<V> to the JRE emul and use those instead of Command? This design seems to parallel some of the patterns in ExecutorService. I could see some of those patterns being useful (like completion queues, which would be useful for staged animations). -Ray
On Thu, Sep 3, 2009 at 7:08 PM, Bruce Johnson <br...@google.com> wrote: > Okay, here's a strawman for a new-and-improved proposal. All these would be > in core. > // "Deferred command" = on the other side of the event loop > interface DeferredCommands { > public static DeferredCommands get(); > > public void add(Command cmd); > public void add(Command cmd, boolean asap); // asap = faster than > setTimeout(0) > public void addPause(); > } > > // "Finally command" = before you end the current stack trace > interface FinallyCommands { > public static FinallyCommands get(); > > public void add(Command cmd); > } > > // "Incremental command" = call repeatedly quickly to avoid SSWs > interface IncrementalCommands { > public static IncrementalCommands get(); > > public void add(Command cmd); > public void add(Command cmd, boolean asap); > } > > // "Timed command" = call based clock time (aka regular old timers) > interface TimedCommands { > public static TimedCommand get(); > > public TimerController scheduleOnce(Command cmd, int millis); > public TimerController scheduleRecurring(Command cmd, int millis); > } > > // Allows optional control over a timer after it's created. > // If the return values in scheduleOnce, etc. aren't used, extra code can > maybe optimize away. > interface TimerController { > public void pause(); > public void resume(); > public void cancel(); > } > > I think that maybe consolidating timers into this mix might be a bit much, > but, then again, if we're graduating "Command" to core, then it seems like > it would be nice to make it the uniform callback interface. > > -- Bruce > > On Thu, Sep 3, 2009 at 9:28 PM, Bruce Johnson <br...@google.com> wrote: > >> I like it a lot Ray. (To be completely honest, I knew you were going to >> say all that, so I decided to sandbag and let you do the typing :-) >> >> I question if it's really appropriate to explicitly say "PreEventLoop" and >> "PostEventLoop" considering that...sometimes...the event loop can actually >> run re-entrantly. Those names sound like a very strong guarantee that I >> don't think we can reliably guarantee. It's more like >> "PreCurrentJavaScriptStackFullyUnwinding" and "PostEventLoop". >> >> Actually, to take a step back (which is my very favorite thing to do), >> there are several kinds of things that could be consolidated: >> >> 1) Single-shot timers >> 2) Recurring timers >> 3) Incremental commands that run as soon as possible after the event loop >> (faster than setTimeout(0)) >> 4) Incremental commands that run after the event loop via setTimeout(0) >> 5) Deferred commands that run as soon as possible after the event loop >> (faster than setTimeout(0)) >> 6) Deferred commands that run after the event loop via setTimeout(0) >> 7) Execute-this-before-you-unwind-the-JS-stack-in-which-it-was-enqueued >> (aka BatchedCommand) >> 8) Arguably, runAsync (although it's purpose is so functionally different >> it would probalby be a mistake to munge it in) >> >> #3 and #5 might look funny, but it is generally possible to run code >> *after* the event loop but *much* sooner than setTimeout(0), which is >> usually clamped to some pretty long duration such as 10ms. The reason you >> wouldn't want to do #3 and #5 as the default for deferred commands is that >> it would keep the CPU overly busy if you did it a bunch in a row. It would >> very likely drain mobile batteries quickly, even. >> >> @Ray (or anyone): Can you think of an awesome way to reconcile those >> behind a consistent API? >> >> >> >> >> >> >> >> On Thu, Sep 3, 2009 at 4:52 PM, Joel Webber <j...@google.com> wrote: >> >>> ++(++Ray) >>> Anything we can do to sensibly get this crap out of .user and into .core >>> (or some other common location) would be very, very good. >>> If, as a side-effect, we could get DeferredCommand to *not* use >>> IncrementalCommand (the latter brings in fairly significant dependencies >>> that are enough to matter for small apps), that would be even better. >>> >>> >>> On Thu, Sep 3, 2009 at 4:46 PM, Scott Blum <sco...@google.com> wrote: >>> >>>> ++Ray. >>>> >>>> >>>> On Thu, Sep 3, 2009 at 4:38 PM, Ray Ryan <rj...@google.com> wrote: >>>> >>>>> The mechanism is just brilliant. I have reservations about the api. >>>>> >>>>> <bikeshed> >>>>> "it seemed kinda nice to have one less type" >>>>> >>>>> Except that we have one more type, BatchedCommand, which looks exactly >>>>> like Command, except with a different name, and you have to subclass it >>>>> rather than implement it... >>>>> >>>>> A simple thing we could do is: >>>>> >>>>> - create com.google.gwt.core.client, >>>>> - change com.google.gwt.user.client.Command to extend the new one >>>>> - deprecate com.google.gwt.user.client.Command >>>>> - And have BatchedCommand accept com.google.gwt.core.client >>>>> >>>>> And the two names, "DeferredComand" and "BatchedCommand", don't give >>>>> much clue as to which does what. And of course BatchedCommand doesn't >>>>> actually provide any batching service. >>>>> >>>>> If we were doing all this from scratch, I suspect we would wind up with >>>>> something like this in core (presuming we're happy with IncrementalCommand >>>>> and addPause): >>>>> >>>>> package com.google.gwt.core.dispatch >>>>> >>>>> public interface Command { >>>>> void execute(); >>>>> } >>>>> >>>>> public interface IncrementalCommand { >>>>> boolean execute(); >>>>> } >>>>> >>>>> public class PreEventLoopDispatcher { >>>>> public static PreEventLoopDispatcher get(); { ... } >>>>> >>>>> public void addCommand(Command c); >>>>> } >>>>> >>>>> public class PostEventLoopDispatcher { >>>>> public static PostEventLoopDispatcher get(); { ... } >>>>> >>>>> public void addCommand(Command c); >>>>> public void addCommand(IncrementalCommand c); >>>>> public void addPause(); >>>>> } >>>>> >>>>> Note the avoidance of statics to make commands more testable, a >>>>> recurring subject. >>>>> >>>>> Seems like we could do this, deprecate the existing classes, and make >>>>> them wrappers around the new. >>>>> >>>>> </bikeshed> >>>>> >>>>> On Wed, Sep 2, 2009 at 11:36 PM, Ray Cromwell >>>>> <cromwell...@gmail.com>wrote: >>>>> >>>>>> >>>>>> Could this also be used as a general pattern to batch DOM updates from >>>>>> multiple Widgets performing updates? e.g. a current approach to avoid the >>>>>> overhead, of say, installing a dozen widgets, is to concatenate all the >>>>>> HTML >>>>>> together, slam it into innerHTML, and then wrap the widgets around the >>>>>> HTML. >>>>>> But this rather breaks the nice OO design people are used to with >>>>>> widgets. >>>>>> Templating is an alternative, but I'm wondering, why can't we make all of >>>>>> the attachment stuff happen via a batch queue. A special optimizer on the >>>>>> queue could even recognize instances of when DOM updates can be coalesced >>>>>> and leverage documentFragment or innerHTML. >>>>>> e.g. >>>>>> >>>>>> VerticalPanel vp = ... >>>>>> vp.add(new Label()) >>>>>> vp.add(new Label()) >>>>>> >>>>>> The objects are constructed, but the HTML mutations are >>>>>> deferred/queued. When adding a DOM mutation to the queue, you could >>>>>> check if >>>>>> existing queue data isOrHasChild the new DOM mutation element, and if so, >>>>>> just modify the queue element (coalesce) rather than appending another >>>>>> queue >>>>>> item. Then, when processing the queue, you only need to add the roots to >>>>>> the >>>>>> DOM, attaching/modifying enmasse. >>>>>> >>>>>> This would preserve the OO-ness of constructing widget hierarchies >>>>>> without requiring 'foreign' string-based templating. >>>>>> >>>>>> -Ray >>>>>> >>>>>> >>>>>> On Wed, Sep 2, 2009 at 5:13 PM, Bruce Johnson <br...@google.com>wrote: >>>>>> >>>>>>> On Wed, Sep 2, 2009 at 6:07 PM, Scott Blum <sco...@google.com>wrote: >>>>>>> >>>>>>>> I do agree with John that we should really discuss how this can be >>>>>>>> implemented. >>>>>>> >>>>>>> >>>>>>> It's already implemented! >>>>>>> >>>>>>> >>>>>>>> Is there some magic trick to make the browser execute a piece of >>>>>>>> code at the time you want, or do we need to go and modify all our >>>>>>>> event code >>>>>>>> (like with the global uncaught exception handler)? >>>>>>> >>>>>>> >>>>>>> No trick, it's as bad as you'd hope it wasn't. On the positive side, >>>>>>> it's already been done -- I'm just augmenting the tests for the various >>>>>>> subsystems such as RequestBuilder and event dispatching to make sure we >>>>>>> tighten the correctness noose as much as possible. >>>>>>> >>>>>>> Longer term, Bob and I both would really like to find a general >>>>>>> mechanism for making this pattern easy to do from any path into a GWT >>>>>>> module >>>>>>> from "the outside", exactly along the lines of what Matt was talking >>>>>>> about. >>>>>>> I think rolling this functionality into gwt-exporter (and then rolling >>>>>>> that >>>>>>> sort of functionality directly into GWT proper) will get us pretty far >>>>>>> down >>>>>>> the road. >>>>>>> >>>>>>> Code review request forthcoming, possibly tomorrow. >>>>>>> >>>>>>> -- Bruce >>>>>>> >>>>>>> >>>>>>> >>>>>> >>>>> >>>>> >>>>> >>>> >>>> >>>> >>> >>> >>> >> > > > > --~--~---------~--~----~------------~-------~--~----~ http://groups.google.com/group/Google-Web-Toolkit-Contributors -~----------~----~----~----~------~----~------~--~---