Ajax queue Backbone js

Go To StackoverFlow.com

10

I am running Backbone js 0.9.2 on Rails 3.2.2,I have a page for adding cost rows.A cost have 3 TextFields: title, description and price.

I am saving each cost on blur.

model.save() gets called multiple times with very short intervals. Which issues one create(post) request then one update(put) request shortly there after. The problem I am experiencing is that PUT request sometimes reaches the server before the POST, the result being that model gets created and persisted twice(duplicates).

To save on blur is the requested behavior, so I need a way to queue up requests. I have read something about Spine js, and that they solve it by some kind of queue. I've also looked in to this, but can't seem to figure this out.

It feels like this should be a common issue, working with "single-page-apps" but can't find anything about it.

2012-04-03 19:53
by Tim Brunsmo


9

You could override the save method and create a queue with a deferred object . For example,

var MDef = Backbone.Model.extend({
    url: "/echo/json/?delay=3",

    initialize: function() {
        this.queue = $.Deferred();
        this.queue.resolve();
    },

    save: function(attrs,options) {
        var m = this; 
        console.log("set "+JSON.stringify(attrs));

        // this.queue = this.queue.pipe with jquery<1.8
        this.queue = this.queue.then(function() {
            console.log("request "+JSON.stringify(attrs));
            return Backbone.Model.prototype.save.call(m, attrs, options);
        });            
    }
});

var m = new MDef();
m.save({title: "a title"});
m.save({description: "a description"});
m.save({price: "a price"});

And a Fiddle : http://jsfiddle.net/nikoshr/8nEUm/

2012-04-04 08:18
by nikoshr
Using this with great results, thank you - Tim Brunsmo 2012-04-26 11:30


3

User debounce from underscore.js.

Creates and returns a new debounced version of the passed function that will postpone its execution until after wait milliseconds have elapsed since the last time it was invoked.

This way it will only fire once after the last blur event.

2012-04-03 20:12
by abraham
That is not a bullet proof solution, it may solve most cases but there is still a chance that data can be lost - Tim Brunsmo 2012-04-03 20:29
@TimBrunsmo, @abraham debounce is right. How will data be lost? You can replace it with _.throttle if you want to force periodic saves - ggozad 2012-04-03 20:40
@ggozad If a field is focused and user choose to leave page, e.g clicking "next" button, there is a chance that blur event never issues a request. If there is a queue, you can check if queue is finished and then let the user pass along - Tim Brunsmo 2012-04-03 21:01
@TimBrunsmo both throttle and debounce will have the effect you want. They do actually queue the function for later execution - ggozad 2012-04-03 21:05
@TimBrunsmo unless you are a financial institue you really don't need anything more redundant. A one or two second debounce will almost never get closed before executing - abraham 2012-04-03 21:09
I've tried it out and it does not work that well... See, even though I am debouncing, if first CREATE request is not finished next request will be a CREATE too (since model still isNew())and i end upp with duplicates - Tim Brunsmo 2012-04-07 22:35
You could ad an extra couple of seconds - abraham 2012-04-09 04:37