Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

jQuery Promises and Backbone

I found this snippet of code that does what I want it to:

var promise = this.model.save();
$.when(promise).then(function() {
     console.log(promise.responseText);
});

I want to get back the responseText from my Backbone call to this.model.save(). This code was documented here. But it's not logging anything, even if I pull a raw text string in the console.log() call.

Could someone please explain in layman's terms what a jQuery promise is? I've read about them, but I don't think I quite got what they were. That might help me understand why this code isn't working for me. If I console.log(promise) in between the first and second lines of code, then I get the responseText. So something is happening in either the $.when or the then that is causing this to go wrong.

EDIT:

After reading the article, I discovered I could do this:

var promise = this.model.save(); 
$.when(promise).then(null, function(obj) {
    console.log(obj.responseText);
});

But I don't understand what the null represents. then seems to take two parameters, a success function and a failure function. But wouldn't the success function be first? I get a 200 response from the server.

like image 385
sehummel Avatar asked Jan 18 '13 20:01

sehummel


2 Answers

So first off, I'm pretty sure you don't need the when part; from the jQuery docs:

The jqXHR objects returned by $.ajax() as of jQuery 1.5 implement the Promise interface, giving them all the properties, methods, and behavior of a Promise (see Deferred object for more information).

Since Promise has a then method already, you can just do:

this.model.save().then(null, function(obj) {
    console.log(obj.responseText);
});

(The fact that the above code almost reads like an English sentence is a major advantage of using Deferreds, for me at least.)

As for your null argument, the docs are again pretty clear. There are three signatures for then (and that's just to cover the different jQuery versions; any given version has less):

deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

deferred.then( doneCallbacks, failCallbacks )

deferred.then( doneCallbacks, failCallbacks [, progressCallbacks ] )

As you can see, all three take the "done" function first, and the failure function second. This does seem to imply that you're getting a failure, which is confusing. One way to avoid the problem is to not use then at all. Instead, try the following:

this.model.save().always(function(obj) {
    console.log(obj.responseText);
});

That will make your function get called no matter what happens. However, you probably should figure out what's going on, so you might want to instead add a success and failure callback to do some debugging:

this.model.save().done(function() {
    // Success case
}).fail(function() {
    // Failure case
});
like image 162
machineghost Avatar answered Nov 04 '22 12:11

machineghost


Because this.model.save returns a promise, you can do the following instead:

this.model.save()
    .done(function(response) {
        console.log("Success!");
    })
    .fail(function(response) {
        console.log("Error!");
    });

(That's easier than the whole $.when bit.)

My guess is that although your response is returning a 200 code, it is still "failing" because the response data type doesn't match up with what you're expecting (what's set in the dataType attribute in the $.ajax call).

like image 7
Lukas Avatar answered Nov 04 '22 14:11

Lukas