- From: Jeremy Orlow <jorlow@chromium.org>
- Date: Wed, 3 Mar 2010 17:12:12 +0000
- To: Kris Zyp <kris@sitepen.com>
- Cc: Joseph Pecoraro <joepeck02@gmail.com>, public-webapps <public-webapps@w3.org>
- Message-ID: <5dd9e5c51003030912i2740743ctdbeede03e9874a5b@mail.gmail.com>
Erm... s/differed/deferred/g On Wed, Mar 3, 2010 at 4:58 PM, Jeremy Orlow <jorlow@chromium.org> wrote: > On Wed, Mar 3, 2010 at 11:01 AM, Jeremy Orlow <jorlow@chromium.org> wrote: > >> On Wed, Mar 3, 2010 at 4:49 AM, Kris Zyp <kris@sitepen.com> wrote: >> >>> -----BEGIN PGP SIGNED MESSAGE----- >>> Hash: SHA1 >>> >>> >>> >>> On 3/1/2010 2:52 PM, Jeremy Orlow wrote: >>> > Thanks for the pointers. I'm actually pretty sold on the general >>> > idea of promises, and my intuition is that there won't be a very >>> > big resource penalty for using an API like this rather than >>> > callbacks or what's currently specced. At the same time, it seems >>> > as though there isn't much of a standard in terms of the precise >>> > semantics and some of the techniques (such as optionally taking >>> > callbacks and not returning a promise if they are supplied) seems >>> > like a decent answer for pure javascript APIs, but maybe not as >>> > good for IDL and a standard like this. >>> > >>> > Do you guys have any recommendations for the precise semantics we'd >>> > use, if we used promises in IndexedDB? To get started, let me list >>> > what I'd propose and maybe you can offer counter proposals or >>> > feedback on what would or wouldn't work? >>> > >>> > >>> > Each method on a ____Request interface (the async ones in the spec) >>> > whose counterpart returns something other than void would instead >>> > return a Promise. >>> >>> Asynchronous counterparts to void-returning synchronous functions can >>> still return promises. The promise would just resolve to undefined, >>> but it still fulfills the role of indicating when the operation is >>> complete. >>> >> >> Good point! Silly me. >> >> >>> > The promises would only have a "then" method which would take in an >>> > onsuccess and onerror callback. Both are optional. The onsuccess >>> > function should take in a single parameter which matches the return >>> > value of the synchronous counterpart. The onerror function should >>> > take in an IDBDatabaseError. If the callbacks are null, undefined, >>> > or omitted, they're ignored. If they're anything else, we should >>> > probably either raise an exception immediately or ignore them. >>> >>> Yes. >>> >> >> Any thoughts on whether we'd raise or ignore improper inputs? I'm leaning >> towards raise since it would be deterministic and silently ignoring seems >> like a headache from a developer standpoint. >> >> >>> > If there's an error, all onerror callbacks would be called with the >>> > IDBDatabaseError. >>> >>> Yes. >>> >>> >>> > Exceptions within callbacks would be ignored. >>> >>> With CommonJS promises, the promise returned by the then() call goes >>> into an error state if a callback throws an exception. For example, >>> >>> someAsyncOperation.then(successHandler, function(){ throw new >>> Error("test") }) >>> .then(null, function(error){ console.log(error); }); >>> >>> Would log the thrown error, effectively giving you a way of catching >>> the error. >>> >>> Are you suggesting this as a simplification so that IndexedDB impls >>> doesn't have to worry about recursive creation of promises? If so, I >>> suppose that seems like a reasonable simplification to me. Although if >>> promises are something that could be potentially reused in other >>> specs, it would be nice to have a quality solution, and I don't think >>> this is a big implementation burden, I've implemented the recursive >>> capabilities in dozen or two lines of JS code. But if burden is too >>> onerous, I am fine with the simplification. >>> >> >> When you say "recursive capabilities" are you just talking about how to >> handle exceptions, or something more? >> >> In terms of exceptions: I don't think it's an >> enormous implementational burden and thus I think it's fine to ignore that >> part of the equation. So the question mainly comes down to whether the >> added complexity is worth it. Can you think of any real-world examples of >> when this capability is useful in promises? If so, that'd definitely help >> us understand the pro's and con's. >> > > 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. > > I'm not sure if this added flexibility is worth the potentially more > confusing and subtle code + the increased API surface area, though. The > more straightforward composability and predictability of promises also seems > appealing. > > So, at this point, I'm actually leaning towards saying all exceptions > should just be swallowed up by the then clause. If a particular > implementation did want to handle these situations, there's nothing stopping > them from using a bit of global state to keep track of it (though I admit > that's less elegent). It's also worth noting that it'd be possible to > implement differed semantics with a wrapper around promises. > > (Just to reiterate, I am not an expert on any of this, so please correct me > if I'm misunderstanding/mischaracterizing. My goal here is to find a > cleaner way to do the IndexedDB async API.) > > >> > 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). >> >> J >> > >
Received on Wednesday, 3 March 2010 17:13:05 UTC