Re: [IndexedDB] Promises (WAS: Seeking pre-LCWD comments for Indexed Database API; deadline February 2)

On Thu, Mar 4, 2010 at 6:37 AM, Jeremy Orlow <jorlow@chromium.org> wrote:

> You are quite right!  I misunderstood how this part of promises worked.
>
> Is there excitement about speccing promises in general?
>

Yes. The starting point for a lot of the commonjs promises work is Tyler's
ref_send promise library, documented at <
http://waterken.sourceforge.net/web_send/#Q>. The commonjs work got more
complicated than this in order to try to accommodate legacy deferred-based
usage patterns within the same framework. While it may have helped adoption
within the commonjs community, IMO this extra complexity should not be in
any standard promise spec. Caja implements Tyler's spec without the extra
complexity, and we're quite happy with it.

I hope to work with Tyler and others to propose this to the EcmaScript
committee as part of a more general proposal for a communicating-event-loops
concurrency and distribution framework for future EcmaScript. Don't hold
your breath though, this is not yet even an EcmaScript strawman. Neither is
there any general consensus on the EcmaScript committee that EcmaScript
should be extended in these directions. In the meantime, I suggest just
using Tyler's ref_send and web_send libraries.



>  If not, it seems a little odd to spec such a powerful mechanism into just
> IndexedDB....and it might be best to spec the simplified version of
> .then(): .then() will return undefined, onsuccess/onerror's return values
> will be swallowed, and any thrown exceptions will be thrown.
>
> This should make it easy to make IndexedDB support full blown promises
> if/whenever they're specced.  (It's not clear to me whether UA support for
> them would offer enough advantages to warrant it.)
>

Note that ref_send exposes the .then() style functionality as a static
.when() method on Q rather than an instance .then() method on promises. This
is important, as it 1) allows resolved values to be used where a promise is
expected, and 2) it protects the caller from interleavings happening during
their Q.when() call, even if the alleged promise they are operating on is
something else.




>
> It sounds like you're OK with such an approach, Kris?
>
> What do others think?
>
> J
>
>
>>  >
>> >     > In terms of speccing, I'm not sure if we can get away with
>> >     speccing
>> >
>> >     > one promise interface or whether we'd need to create one for each
>> >
>> >     > type of promise.
>> >
>> >     Certainly the intent of promises is that there is exists only one
>> >     generic promise interface that can be reused everywhere, at
>> >     least from
>> >     the JS perspective, not sure if the extra type constraints in IDL
>> >     demand multiple interfaces to model promise's effectively
>> >     parameterized generic type form.
>> >
>> >
>> > Unfortunately, I don't really know.  Before we try speccing it, I'll
>> > definitely see if any WebIDL experts have suggestions.
>> >
>> >
>> > Also, do we want to explicitly spec what happens in the following case?
>> >
>> > window.indexedDB.open(...).then(
>> >     function(db) {  db.openObjectStore("a").then( function(os) {
>> > alert("Opened a"); } ) }
>> > ).then(
>> >     function(db) { alert("Second db opened"); }
>> > );
>> >
>> > Clearly the first function(db) is called first.  But the question is
>> > whether it'd be a race of which alert is called first or whether the
>> > "Second db opened" alert should always be shown first (since clearly
>> > if the first is called, the second _can_ be fired immediately
>> > afterwards).
>> >
>> > I'm on the fence about whether it'd be useful to spec that the
>> > entire chain needs to be called one after the other before calling
>> > any other callbacks.  Does anyone have thoughts on whether this is
>> > useful or not?  If we do spec it to call the entire chain, then what
>> > happens if inside one of the callbacks, something is added to the
>> > chain (via another .then() call).
>> >
>> Specing the order of multiple events in the event loop seems like it
>> would be excessive burden on implementors, IMO.
>>
>> > I've been talking to a co-worker here who seems to know a decent
>> > amount about promises (as implemented in E) and some about differed
>> > (as implemented in Python's Twisted library).  From talking to him,
>> > it seems that my original suggestion for not handling exceptions
>> > thrown inside a .then() callback is the way to go.
>> >
>> > It seems as though promises put a lot of weight on composability and
>> > making it so that the order of .then() calls not mattering.  This
>> > means that you can then pass promises to other async interfaces and
>> > not have to worry about different timings leading to different
>> > results.  It also means that if you pass a promise into multiple
>> > consumers (say, javascript libraries) you don't need to worry about
>> > one using a promise in a way that screws up another.
>> >
>> > Differed seems to be more expressive and flexible.  For example,
>> > instead of doing this:
>> >
>> > window.indexedDB.open(...).then(
>> >     function(db) {  db.openObjectStore("a").then(
>> >         function(os) { os.get("x").then(
>> >             function(value) { alert("Value: " + value); }
>> >         ) }
>> >     ) }
>> > );
>> >
>> > I could do this:
>> >
>> > window.indexedDB.open(...).then(
>>
>> >     function(db) { return db.openObjectStore("a"); }    // Note the
>> > return value is passed on to the next step.
>> > ).then(
>> >     function(os) { return os.get("x"); }
>> > ).then(
>> >     function(value) { alert("Value: " + value); }
>> > );
>> >
>> > And I can also have any one of those throw an error which would be
>> > passed on to the rest of the chain, much like nested try/catch
>> > blocks in single threaded code.
>>
>>
>> Yes, this type of chaining is exactly the intent of the promises I
>> have suggested. Having the return value of the thrown error passed on
>> to the rest of the chain is most intuitive IMO (since it is analagous
>> to synchronous call stacks) and what I would recommend. One thing that
>> Twisted got wrong (but E got right) was that the callbacks in
>> Twisted's deferred mutate the original deferred itself which causes
>> difficult to contain side-effects, whereas the callback's return value
>> should only affect a newly generated returned promise (maintaining
>> proper functional data flow of outputs not affecting inputs).
>>
>>
>> - --
>> Kris Zyp
>> SitePen
>> (503) 806-1841
>> http://sitepen.com
>> -----BEGIN PGP SIGNATURE-----
>> Version: GnuPG v1.4.9 (MingW32)
>> Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org/
>>
>> iEYEARECAAYFAkuOywcACgkQ9VpNnHc4zAzWCQCgiTl7S2Iv477vuzH2+IG6raMc
>> jrsAoL4aUfbG7WWHUktwbid8MMw0C5C6
>> =PVcB
>> -----END PGP SIGNATURE-----
>>
>>
>


-- 
    Cheers,
    --MarkM

Received on Thursday, 4 March 2010 17:36:04 UTC