-
-
Save mattheworiordan/1037984 to your computer and use it in GitHub Desktop.
(function() { | |
Backbone.Model.prototype._save = Backbone.Model.prototype.save; | |
Backbone.Model.prototype.save = function(attrs, options) { | |
var that = this; | |
if (!options) { options = {}; } | |
if (this.savingNewRecord) { | |
// store or replace last PUT request with the latest version, we can safely replace old PUT requests with new ones | |
// but if there are callbacks from a previous PUT request, we need to make sure they are all called as well | |
_(['success','error']).each(function(event) { | |
// convert all callbacks to a single array of callbacks) | |
var existingCallbacks = that.putQueue ? that.putQueue.options[event] : []; | |
options[event] = _.compact( existingCallbacks.concat(options[event]) ); | |
}); | |
this.putQueue = { attributes: _.extend({}, that.attributes, attrs), options: options }; | |
} else { | |
if (this.isNew()) { | |
// saving a new record so we need to wait for server to respond and assign an ID before the model is saved again | |
this.savingNewRecord = true; | |
// store the old callback and overwrite so we can catch the success/error event when savint this model | |
_(['success','error']).each(function(event) { | |
var oldEventCallback = options[event]; | |
options[event] = function(model, response) { | |
that.savingNewRecord = false; | |
// check if callback for this model save exists and if so execute the callback | |
if (oldEventCallback) { oldEventCallback.apply(this, model, response); } | |
// if there is a PUT waiting to fire, fire it now | |
if (that.putQueue) { | |
// as PUT builds up callbacks as arrays, lets create a callback which executes all the callbacks | |
_(['success','error']).each(function(callBackEvent) { | |
var callbacks = _.clone(that.putQueue.options[callBackEvent]); | |
that.putQueue.options[callBackEvent] = function(model, response) { | |
var callbackThis = this; | |
_(callbacks).each(function(callback) { | |
callback.apply(callbackThis, model, response); | |
}) | |
}; | |
}); | |
Backbone.Model.prototype.save.call(that, _.extend({}, that.attributes, that.putQueue.attributes), that.putQueue.options); | |
} | |
}; | |
}); | |
} | |
Backbone.Model.prototype._save.call(this, attrs, options); | |
} | |
}; | |
}()); |
@philfreo, what do you think of this version?
It will only do one PUT request whilst waiting for a isNew() record to save. I've tested it in my environment and it seems to work OK. As you will see, it's pretty much a complete rewrite, and quite robust as even though it compacts all PUT requests into one, it still calls all the callbacks passed in.
There are some risks with this code though:
- If you explicitly set attributes in a previous PUT request as part of your save call, and then do another save the attributes you passed into your first request may be lost
- If the POST request updates fields other than ID i.e. say email is changed from matt to [email protected] in the response, this too could be lost
- If the PUT requests have an explicit value set to trigger an event, that too could be lost as the future PUT requests may not set that value.
All of these situations above are edge cases, and largely existed before this latest version of the Gist, but worth pointing out anyway.
Perhaps something else in my app is interferring with its behavior, but I just plugged in the latest version here and it just doesn't work for me (get tons of PUT requests fired immediately)
I tried your latest version again after some other cleanup in my app, and I get this:
http://cl.ly/image/2E1P1V3O2V38
(which includes some parallel requests -- and also it's queuing up way too many still - later ones don't seem to be canceling earlier ones)
If i use this code $.when(model.save()).done(callback)
doesn't work.
And evens don't work: model.on('success', callback)
Here is possible fix, but i'm not sure about events triggering: https://gist.github.com/3873386
@philfreo, I agree, that is the right approach. I will make some changes to this Gist shortly and you can tell me what you think.