documentcloud/backbone — pull request #1567 by abdR (2012-08-21 01:33:07+00:00)
Title: add deferred request to models or collections for race condutions

** About this request **

This solves some problems when user interacts backbone rapidly(user click all buttons faster than servers response). This is related to #1325 and #1468. This has some problems.Look at the commits and comments.This pull request is first commit that improving backbone's [asynchronous UI feature](http://alexmaccaw.com/posts/async_ui).

** what are you offering Incoming requests **

Backbone offer asynchronous user interfaces but it is not clean when it
comes to rapid model syncing and id generation.[Spine](spinejs.com) offers approximately
similar features, but Spine focus asynchronous interfaces more than backbone.
I do not want to switch to Spine because I was delving deeper to the backbone by
reading annotated source code.After all, I decided to strength asynchronous
UI feature of backbone by whether pulling some requests or writing tiny plug-in

**Implementing asynchronous user interfaces**

if you create a model then you call Backbone.sync
indirectly, (calling model.fetch,save,destroy collection.fetch,create)
you want to sync with server.Unfortunately there is some problems.

1. if your model isNew, you cant call Backbone.sync with delete method
your server is completely unaware this deletion when dealing with your
update or create methods.
Thus, client is under the impression that s/he deleted the model,
but server don't and won't delete.
SOLUTION: give an id into Backbone.sync on create method.
probably give cid or guid as a pseudo-id.
this causes second problem
''' javascript
// In Backbone.sync
if (!options.data && model && (method === 'create')) {
model.set({id:model.cid}, {silent:true});
}
'''

2. if your methods cannot reach to the server in their order of sending,
some race conditions may happen.
For example, your delete method with pseudo-id is received by server
before your create method that will turn to the client with real id.
second example is sending read method with filter A
then sending read method with filter B. if second read method
returns to the server first, client see filter A when want to see filter B
SOLUTION: send all methods one at a time but do this efficiently.
send one request then defer requests until response. if user send another
request when there is a deferred request, override previously deferred one
because user only wants the last change on the model or collection.
Finally response comes, only change pseudo-id of deferred to the real id
then send deferred request
''' javascript
// In commited success
if (arguments[0].id && model.id === model.cid) {
model._deferredRequest[1].set({id:arguments[0].id}, {silent:true})
}
'''