Lorraine Bernard
Lorraine Bernard

Reputation: 13420

How to avoid a race condition when keyup event is sent

I have a function matcher which is called every time a keyup event is sent.

This function belongs to a module which look like this (1).
what if another call is done before the fetching is completed?
How can I solve this problem in this module (1)?


(1)

(function ($, UserCollection) {

    var userCollection;

    var matcher = function (request, response) {
        if (!userCollection) {
            userCollection = new UserCollection();
            userCollection.fetch();
        } else {
            isMatched(request, response);
        }
    };

    return matcher;
}(jquery, UserCollection));

Upvotes: 3

Views: 538

Answers (3)

nikoshr
nikoshr

Reputation: 33364

I'll take a different, probably overkill, approach and use the jqXHR object returned by collection.fetch.

var Matcher=(function($,UserCollection) {

    var xhr=null, userCollection=null;

    // matching against a defined ID for testing purpose
    function isMatched(id) {
        return userCollection.get(id);
    }

    // the request would be an ID in my example,
    // and the callback is the function invoked when the collection is fetched
    function matcher(request, callback) {
        if (!xhr) {
            userCollection = new UserCollection();

            // fetch returns a handy xhr object used for the deferred
            xhr=userCollection.fetch(); 
        }

        xhr.then(function() {
            callback(isMatched(request));
        });
    }       

    return matcher;

})(jQuery, UserCollection);

If the xhr is already resolved, the callback is immediately invoked, if not, it will be when the request completes : see jQuery.Deferred for more info.

And you would use it as

Matcher(1,console.log);
Matcher(2,console.log);

And a Fiddle http://jsfiddle.net/EWSAV/1/

Upvotes: 2

Christoph
Christoph

Reputation: 51201

As long as you run synchronous actions this should be no problem, because the events get executed in a timely manner.

However, you could add a second variable which indicates if a matching is in progress.

Something like this:

(function ($, UserCollection) {

    var userCollection;
    var inProgress = false;

    var matcher = function (request, response) {
        if (!inProgress){
           if (!userCollection) {
               inProgress = true;
               userCollection = new UserCollection();
               userCollection.fetch();
           } else {
               isMatched(request, response);
           }
           // inProgress = false; - after your asynchonous code is executed
        }
    };

    return matcher;
}(jquery, UserCollection));

This code probably won't work, but I think you got the idea.

This approach however might require your asynchronous script to be in the same scope to have access to inProgress. The better option might be to work with callbacks on the fetch:

userCollection.fetch({ success:function(){inProgress=false} });

Upvotes: 1

Adi
Adi

Reputation: 5179

According to Backbone.js documentation, fetch() accepts a callback function to be called after a successful "fetch". So you can have a global variable indicating the state of the current "fetch". This is the basic idea, I think you can work your way from here

fetching = false;
//Event fired ->
if (!fetching ){
fetching = true;
..fetch({success: function(){fetching = false;}});
}

Upvotes: 0

Related Questions