Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to transfer all the handlers from one deferred to another?

Let's say I have a $.Deferred and a jqXHR object. Is there a way to transfer all the handlers bound to the deferred (then, always, done, fail) over to the XHR object (which, as I understand it, is an extension of Deferred)?


Here's what I had in mind:

$.ajaxOne = function(options) {
    var xhr = null;
    return function() {
        if(xhr) xhr.abort();
        xhr = $.ajax(options).always(function() {
            xhr = null;
        });
    }
}

I wanted to create a function, similar to $.ajax, except that if you call it multiple times in rapid succession, it will abort the last request and only complete the most recent one. This is useful in many scenarios where you want to validate a user's input.

For example, you might want to check if a username is taken, but if they start typing in the username field again after you've started your ajax call, you don't care about the last result, only the most recent one.

Also, I don't think requests are guaranteed to return in the same order they went out (I suppose depending on your server setup), so you could have a syncing issue as well.

Anyway, the problem with the above code is that because it returns a function, you can execute your ajax call whenever you like, but you can't bind your completion handlers to it. So I have to somehow mix the deferred handlers in and rebind them to the XHR object.

like image 928
mpen Avatar asked Oct 31 '13 17:10

mpen


People also ask

Where should we use * Defer * In the following code?

The use of defer in the first line of the main function causes that statement to be postponed until the end of the function. Hence, it is executed in the last.

Does defer run after return?

A defer statement defers the execution of a function until the surrounding function returns. The deferred call's arguments are evaluated immediately, but the function call is not executed until the surrounding function returns.

What is the point of Defer in Go?

In Golang, the defer keyword is used to delay the execution of a function or a statement until the nearby function returns. In simple words, defer will move the execution of the statement to the very end inside a function.


1 Answers

Let's say I have a $.Deferred and a jqXHR object. Is there a way to transfer all the handlers bound to the deferred (then, always, done, fail) over to the XHR object (which, as I understand it, is an extension of Deferred)?

More or less, yes, but not in the way you expected. Instead of "moving handlers", you just resolve the deferred (that has the handlers) with the XHR deferred. This will make the deferred adopt the state of the ajax promise - or not, since jQuery is not Promise A+-compatible. So you will need to put the triggers as handlers manually:

var deferred = $.Deferred(),
    xhr = $.ajax(…);
xhr.done(deferred.resolve).fail(deferred.reject).progress(deferred.notify);

However, a use like that is discouraged, just use xhr wherever you needed deferred - they're equal. Or use xhr.then() to create a brand new promise object that resolves exactly like xhr will.

Anyway, the problem with the above code is that because it returns a function, you can execute your ajax call whenever you like, but you can't bind your completion handlers to it. So I have to somehow mix the deferred handlers in and rebind them to the XHR object.

You still can return each xhr object from that returned function, and bind your handlers to that. In case it is aborted, its error handlers will be called.

$.ajaxOne = function(options) {
    var xhr = null;
    return function(name) {
        options.data = name;
        if (xhr) xhr.abort();
        return xhr = $.ajax(options).always(function() {
//      ^^^^^^
            xhr = null;
        });
    }
}
var checkUserAccount = $.ajaxOne({…});
$input.keyup(function(e) {
    checkUser(this.value).done(function(ajaxResult) {
        // do anything here with the ajaxResult from the latest call
        // if there was another keyup event, this callback never fires
    });
});

Also, I don't think requests are guaranteed to return in the same order they went out (I suppose depending on your server setup), so you could have a syncing issue as well.

Not if you call abort on each old one when the function is called again - that will hold the invariant that there is only at most one active ajax request at a time.

I wanted to create a function, similar to $.ajax, except that if you call it multiple times in rapid succession, it will abort the last request and only complete the most recent one.

Sounds pretty much like an event stream. You will want to have a look at Functional Reactive Programming!

like image 76
Bergi Avatar answered Oct 13 '22 23:10

Bergi