Re: [IndexedDB] Events and requests

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:25:06 UTC