For a Backbone.js project that I’m working on, I needed to implement a model where save requests to the backend are called sequentially, i.e. one after another. This can be necessary or useful for the following reasons:

  1. State and order of execution. Let’s assume a client-side application where a user performs two actions that send two Ajax requests. Request A adds an item and request B removes that item. Because of its asynchronous nature, it is possible that request B is handled before request A is finished, because request A takes more time for whatever reason, even though it’s sent first. Request B will result in an error, and leads to unexpected behavior in the user interface. In this scenario, you need to make sure that request A is finished before request B is sent and update your view accordingly.

  2. Synchronous execution. Sometimes you simply don’t need multiple parallel requests. For instance, if you have files that are uploaded and are read one by one, but you want to queue these requests before they are being sent to the server.

  3. Server load. This shouldn’t be your primary concern when you implement something like this, but there are situations where parallel requests can be detrimental to performance, like uploading multiple high-resolution images and generating thumbnails on the fly. You’ll want to fix this server-side, but it can be helpful to consider client-side implications.

Here’s an example of a Backbone model where it’s save calls (which are Ajax requests) are chained:

var ShoppingBasket = Backbone.Model.extend({

    url: '/your/api/url',

    isSaving: false,

    chain: [],

    initialize: function() {
        this.listenTo(this, 'sync', this.onAjaxComplete);
        this.listenTo(this, 'error', this.onAjaxComplete);
    },

    // override Backbone save method
    save: function(attributes, options) {
        if (!this.isSaving) {
            // no unfinished request, call "super" save method
            this.isSaving = true;
            Backbone.Model.prototype.save.apply(this, [attributes, options]);
        } else {
            // unfinished request, add changed attributes to chain
            this.chain.push([attributes, options]);
        }
    },

    callChain: function() {
        // remove first item from array and pass arguments to save method
        return this.chain.length ? this.save.apply(this, this.chain.shift()) : false;
    },

    onAjaxComplete: function() {
        this.isSaving = false;
        this.callChain();
    }

});

Note that in this example an error callback isn’t implemented, and more importantly, make sure that the attributes hash is not mutated before it is sent to the server. You can pass object literals directly, like shoppingBasket.save({items: ...}) instead of shoppingBasket.save(data), or use the _.clone() function from Underscore.js to clone the object.

While the example above is very Backbone specific, you can easily translate this pattern to different situations that don’t involve Ajax, for example to chain animations. As long as you have an object that keeps track of all the calls in an array and loop through them one by one.