- From: Jonas Sicking <jonas@sicking.cc>
- Date: Mon, 10 Jan 2011 14:31:11 -0800
- To: Keean Schupke <keean@fry-it.com>
- Cc: ben turner <bent.mozilla@gmail.com>, Jeremy Orlow <jorlow@chromium.org>, Webapps WG <public-webapps@w3.org>
This seems like something better suggeseted to the lists at ECMA where javascript (or rather ECMAScript) is being standardized. I hardly think that a database API like indexedDB is the place to redefine how javascript should handle asynchronous programming. / Jonas On Mon, Jan 10, 2011 at 2:26 PM, Keean Schupke <keean@fry-it.com> wrote: > Just to correct my cut and paste error, that was of course supposed to be: > var y = do { > result1 <- db.transaction(["foo"]).objectStore("foo").getM(mykey1); > result2 <- db.transaction(["foo"]).objectStore("foo").getM(mykey2); > unit(result1 + result2); > } > > Cheers, > Keean. > On 10 January 2011 22:24, Keean Schupke <keean@fry-it.com> wrote: >> >> Okay, sorry, the original change seemed sensible, I guess I didn't see how >> you got from there to promises. >> >> Here's some fun to think about as an alternative though: >> >> Interestingly the pattern of multiple callbacks, providing each callback >> is passed zero or one parameter forms a Monad. >> So for example if 'unit' is the constructor for the object returned from >> "get" then onsuccess it 'bind' and I can show that these obey the 3 monad >> laws. Allowing composability of callbacks. So you effectively have: >> var x = db.transaction(["foo"]).objectStore("foo").getM(mykey); >> var y = >> db.transaction(["foo"]).objectStore("foo").getM(mykey1).bind(function(result1) >> { >> >> db.transaction(["foo"]).objectStore("foo").getM(mykey2).bind(function(result2) >> { >> unit(result1 + result2); >> }); >> }); >> The two objects returned "x" and "y" are both the same kind of object. y >> represents the sum or concatination of the results of the lookups "mykey1" >> and "mykey2". You would use it identically to using the result of a single >> lookup: >> x.bind(function(result) {... display the result of a single lookup ...}); >> y.bind(function(result) {... display the result of both lookups ...}); >> >> If we could then have some syntactic sugar for this like haskell's do >> notation we could write: >> var y = do { >> db.transaction(["foo"]).objectStore("foo").getM(mykey1); >> result1 <- db.transaction(["foo"]).objectStore("foo").getM(mykey2); >> result2 <- db.transaction(["foo"]).objectStore("foo").getM(mykey2); >> unit(result1 + result2); >> } >> Which would be a very neat way of chaining callbacks... >> >> Cheers, >> Keean. >> >> On 10 January 2011 22:00, Keean Schupke <keean@fry-it.com> wrote: >>> >>> Whats wrong with callbacks? To me this seems an unnecessary complication. >>> Presumably you would do: >>> var promise = db.transaction(["foo"]).objectStore("foo").get(mykey); >>> var result = promise.get(); >>> if (!result) { >>> promise.onsuccess(function(res) {...X...}); >>> } else { >>> ...Y... >>> } >>> >>> So you end up having to duplicate code at X and Y to do the same thing >>> directly or in the context of a callback. Or you define a function to >>> process the result: >>> var f = function(res) {...X...}; >>> var promise = db.transaction(["foo"]).objectStore("foo").get(mykey); >>> var result = promise.get(); >>> if (!result) { >>> promise.onsuccess(f); >>> } else { >>> f(result) >>> }; >>> But in which case what advantage does all this extra clutter offer over: >>> >>> db.transaction(["foo"]).objectStore("foo").get(mykey).onsuccess(function(res) >>> {...X...}); >>> >>> I am just wondering whether the change is worth the added complexity? >>> >>> Cheers, >>> Keean. >>> >>> On 10 January 2011 21:31, Jonas Sicking <jonas@sicking.cc> wrote: >>>> >>>> I did some outreach to developers and while I didn't get a lot of >>>> feedback, what I got was positive to this change. >>>> >>>> The basic use-case that was brought up was implementing a promises >>>> which, as I understand it, works similar to the request model I'm >>>> proposing. I.e. you build up these "promise" objects which represent a >>>> result which may or may not have arrived yet. At some point you can >>>> either read the value out, or if it hasn't arrived yet, register a >>>> callback for when the value arrives. >>>> >>>> It was pointed out that this is still possible with how the spec is >>>> now, but it will probably result in that developers will come up with >>>> conventions to set the result on the request themselves. This wouldn't >>>> be terribly bad, but also seems nice if we can help them. >>>> >>>> / Jonas >>>> >>>> On Mon, Jan 10, 2011 at 8:13 AM, ben turner <bent.mozilla@gmail.com> >>>> wrote: >>>> > FWIW Jonas' proposed changes have been implemented and will be >>>> > included in Firefox 4 Beta 9, due out in a few days. >>>> > >>>> > -Ben >>>> > >>>> > On Fri, Dec 10, 2010 at 12:47 PM, Jonas Sicking <jonas@sicking.cc> >>>> > wrote: >>>> >> I've been reaching out to get feedback, but no success yet. Will >>>> >> re-poke. >>>> >> >>>> >> / Jonas >>>> >> >>>> >> On Fri, Dec 10, 2010 at 4:33 AM, Jeremy Orlow <jorlow@chromium.org> >>>> >> wrote: >>>> >>> Any additional thoughts on this? If no one else cares, then we can >>>> >>> go with >>>> >>> Jonas' proposal (and we should file a bug). >>>> >>> J >>>> >>> >>>> >>> On Thu, Nov 11, 2010 at 12:06 PM, Jeremy Orlow <jorlow@chromium.org> >>>> >>> wrote: >>>> >>>> >>>> >>>> On Tue, Nov 9, 2010 at 11:35 AM, Jonas Sicking <jonas@sicking.cc> >>>> >>>> wrote: >>>> >>>>> >>>> >>>>> Hi All, >>>> >>>>> >>>> >>>>> One of the things we briefly discussed at the summit was that we >>>> >>>>> should make IDBErrorEvents have a .transaction. This since we are >>>> >>>>> allowing you to place new requests from within error handlers, but >>>> >>>>> we >>>> >>>>> currently provide no way to get from an error handler to any >>>> >>>>> useful >>>> >>>>> objects. Instead developers will have to use closures to get to >>>> >>>>> the >>>> >>>>> transaction or other object stores. >>>> >>>>> >>>> >>>>> Another thing that is somewhat strange is that we only make the >>>> >>>>> result >>>> >>>>> available through the success event. There is no way after that to >>>> >>>>> get >>>> >>>>> it from the request. So instead we use special event interfaces >>>> >>>>> with >>>> >>>>> supply access to source, transaction and result. >>>> >>>>> >>>> >>>>> Compare this to how XMLHttpRequests work. Here the result and >>>> >>>>> error >>>> >>>>> code is available on the request object itself. The 'load' event, >>>> >>>>> which is equivalent to our 'success' event didn't supply any >>>> >>>>> information until we recently added progress event support. But >>>> >>>>> still >>>> >>>>> it only supplies information about the progress, not the actual >>>> >>>>> value >>>> >>>>> itself. >>>> >>>>> >>>> >>>>> One thing we could do is to move >>>> >>>>> >>>> >>>>> .source >>>> >>>>> .transaction >>>> >>>>> .result >>>> >>>>> .error >>>> >>>>> >>>> >>>>> to IDBRequest. Then make "success" and "error" events be simple >>>> >>>>> events >>>> >>>>> which only implement the Event interface. I.e. we could get rid of >>>> >>>>> the >>>> >>>>> IDBEvent, IDBSuccessEvent, IDBTransactionEvent and IDBErrorEvent >>>> >>>>> interfaces. >>>> >>>>> >>>> >>>>> We'd still have to keep IDBVersionChangeEvent, but it can inherit >>>> >>>>> Event directly. >>>> >>>>> >>>> >>>>> The request created from IDBFactory.open would return a IDBRequest >>>> >>>>> where .transaction and .source is null. We already fire a IDBEvent >>>> >>>>> where .source is null (actually, the spec currently doesn't define >>>> >>>>> what the source should be I see now). >>>> >>>>> >>>> >>>>> >>>> >>>>> The only major downside with this setup that I can see is that the >>>> >>>>> current syntax: >>>> >>>>> >>>> >>>>> db.transaction(["foo"]).objectStore("foo").get(mykey).onsuccess = >>>> >>>>> function(e) { >>>> >>>>> alert(e.result); >>>> >>>>> } >>>> >>>>> >>>> >>>>> would turn into the slightly more verbose >>>> >>>>> >>>> >>>>> db.transaction(["foo"]).objectStore("foo").get(mykey).onsuccess = >>>> >>>>> function(e) { >>>> >>>>> alert(e.target.result); >>>> >>>>> } >>>> >>>>> >>>> >>>>> (And note that with the error handling that we have discussed, the >>>> >>>>> above code snippets are actually plausible (apart from the alert() >>>> >>>>> of >>>> >>>>> course)). >>>> >>>>> >>>> >>>>> The upside that I can see is that we behave more like >>>> >>>>> XMLHttpRequest. >>>> >>>>> It seems that people currently follow a coding pattern where they >>>> >>>>> place a request and at some later point hand the request to >>>> >>>>> another >>>> >>>>> piece of code. At that point the code can either get the result >>>> >>>>> from >>>> >>>>> the .result property, or install a onload handler and wait for the >>>> >>>>> result if it isn't yet available. >>>> >>>>> >>>> >>>>> However I only have anecdotal evidence that this is a common >>>> >>>>> coding >>>> >>>>> pattern, so not much to go on. >>>> >>>> >>>> >>>> Here's a counter proposal: Let's add .transaction, .source, and >>>> >>>> .result >>>> >>>> to IDBEvent and just specify them to be null when there is no >>>> >>>> transaction, >>>> >>>> source, and/or result. We then remove readyState from IDBResult as >>>> >>>> it >>>> >>>> serves no purpose. >>>> >>>> What I'm proposing would result in an API that's much more similar >>>> >>>> to what >>>> >>>> we have at the moment, but would be a bit different than XHR. It >>>> >>>> is >>>> >>>> definitely good to have similar patterns for developers to follow, >>>> >>>> but I >>>> >>>> feel as thought the model of IndexedDB is already pretty different >>>> >>>> from XHR. >>>> >>>> For example, method calls are supplied parameters and return an >>>> >>>> IDBRequest >>>> >>>> object vs you using new to create the XHR object and then making >>>> >>>> method >>>> >>>> calls to set it up and then making a method call to start it. In >>>> >>>> fact, if >>>> >>>> you think about it, there's really not that much XHR and IndexedDB >>>> >>>> have in >>>> >>>> common except that they use event handlers. >>>> >>>> As for your proposal, let me think about it for a bit and forward >>>> >>>> it on to >>>> >>>> some people I know who are playing with IndexedDB already. >>>> >>>> J >>>> >>> >>>> >> >>>> >> >>>> > >>>> >>> >> > >
Received on Monday, 10 January 2011 22:32:05 UTC