Re: [IndexedDB] Callback order

I think determinism is most important for the reasons you cited.  I think
advanced, performance concerned apps could deal with either semantics you
mentioned, so the key would be to pick whatever is best for the normal case.
 I'm leaning towards thinking firing in order is the best way to go because
it's the most intuitive/easiest to understand, but I don't feel strongly
about anything other than being deterministic.

J

On Fri, Jun 18, 2010 at 4:08 PM, Jonas Sicking <jonas@sicking.cc> wrote:

> Hi All,
>
> One thing that we've talked a bit about at mozilla is about in which
> order asynchronous events should fire. I.e. for code like:
>
> results = [];
> trans = db.transaction(["mystore"]);
> trans.objectStore("mystore").get(1).onsuccess = function(e) {
>  results.push(e.result);
> }
> trans.objectStore("mystore").get(17).onsuccess = function(e) {
>  results.push(e.result);
> }
>
> Which order should the two onsuccess event callbacks fire in?
>
> We could say that the order is undefined. This gives the
> implementation the freedom to fire any even has soon as it possibly
> can and is seemingly the best choice for performance. However this has
> the significant downside that we don't have cross-browser defined
> behavior.
>
> In fact, it's likely that in many implementations the above callback
> order would always be that the callback for the get(1) will fire
> before the callback to get(17). This would be the case if the
> indexedDB store was managed on a single, but separate, thread or
> process which does all the reading/writing in the backend database.
>
> This makes it very likely that authors will come to depend on this
> being the order, and if any implementation tries to somehow optimize
> and create out-of-order firing, then that will lead to sites breaking.
>
> So here we could define the callback order to be that of the order in
> which requests are scheduled without loss of performance.
>
> However a tricker situation is cursors. Consider for example code such as:
>
> results = [];
> trans = db.transaction(["candysales", "kids"]);
> trans.objectStore("candysales").openCursor(range).onsuccess = function(e) {
>  cursor = e.result;
>  if (cursor) {
>     var obj = { candyType: cursor.value.candyType }
>     results.push(obj);
>     trans.objectStore("kids").get(cursor.value.kidId).onsuccess =
> function(e) {
>       obj.kidName = e.result;
>     }
>     cursor.continue();
>  }
> }
>
> or
>
> trans = db.transaction(["opensales", "closedsales"], READ_WRITE);
> trans.objectStore("opensales").openCursor(range).onsuccess = function(e) {
>  cursor = e.result;
>  if (cursor) {
>    trans.objectStore("closedsales").add(cursor.value);
>    cursor.remove();
>    cursor.continue();
>  }
> }
>
> In these cases for each cursor move, another request is made. If we
> were to fire event callbacks in the order the requests are made, it
> would mean that we can't fire the second cursor-success until the get
> or put has succeeded.
>
> But it is very reasonable to expect that cursors can be implemented by
> reading a large number of entries from the database at once and send
> them all to the thread where the consumer is running. It would then
> not need to round-trip to the indexedDB thread on each call to
> cursor.continue();
>
> In such an implementation there would be a very large overhead to have
> to wait for the get/add callback to finish before firing the success
> callback for each cursor callback.
>
> We could simply say that all cursor callbacks can fire in any order.
> However, as usual, this is likely to lead to cross browser differences
> and code only working in one browser.
>
> Alternatively we can say that having to wait for other callbacks is
> ok. This still allows code that only iterates over an objectStore
> using a cursor, without performing any other requests in the meantime,
> can still execute at full speed. Only more advanced examples like the
> two above take a performance hit.
>
> Or we can define that all cursor callbacks are always fired before any
> other scheduled callbacks. So in the two examples above, as soon as
> the cursor.continue() call occurs, all other pending callbacks are
> prevented until the cursor callback has been fired. Which in an
> implementation which reads many cursor values at the same time, is
> possibly immediately.
>
> So in the above two examples all the cursor callbacks would fire
> before any of the .get/.add callbacks are fired.
>
> Note that we can make the definition be that the cursor has to iterate
> all the way through before any other callbacks fire since the webpage
> might not always call cursor.continue(). See for example the last
> example in
> http://docs.google.com/document/pub?id=1I__XnwvvSwyjvxi-FAAE0ecnUDhk5DF7L2GI6O31o18
>
> This certainly add a bit of complexity to the implementation. However
> it allows us to keep high performance and a defined deterministic
> firing order.
>
> Interested to hear your feedback.
>
> / Jonas
>
>

Received on Saturday, 19 June 2010 02:02:01 UTC