Pass extra parameters to jquery ajax promise callb

2019-02-05 18:25发布

问题:

This question already has an answer here:

  • Pass an extra argument to a callback function 4 answers

I need to pass an extra parameter to the .done promise callback of a jquery ajax call:

$.post("MyUrl", JSON.stringify(data))
        .done(onMyUrlLoaded);

The standard callback, would be like this:

function onMyUrlLoaded(data, textStatus, jqXHR) { /* function code */ };

But I need to pass an extra parameter to my callback, like this:

function onMyUrlLoaded(data, textStatus, jqXHR, extraParam) { /* code */ };

How can I do it?

NOTE: this question is not a duplicate, because it's specifically about promise callbacks. Besides this question is two years older than the one which is said to duplicate, and gives a much more thorough answer, and an specifica answer regarding promises.

回答1:

I've discovered that it's really easy including a new indirection level, just like this:

var extraParam = 'xyz';

$.post("MyUrl", JSON.stringify(data))
        .done(function(a,b,c) { onMyUrlLoaded(a, b, c, extraParam); });

In this way, the callback will receive the extraParam, besides the three standard parameters.

Of course, this can also be done if the promise is stored in a variable, for example one returned by a function, like this:

function getUrl() {
  // some code ...
  var promise = $.post("MyUrl", JSON.stringify(data));
  return promise;
}

This can be invoked and used like this:

var promise = getUrl();
var extraParam = 'xyz';
promise.done(function(a,b,c) { onMyUrlLoaded(a, b, c, extraParam); });

There is a shorter syntax for doing this, which consist in using bind.

When you call bind in a function, you get a new function. The first parameter passed to bind will become this inside the body of the return function. The additional parameters will be prepended to the original arguments.

The following code shows how to use bind. For TL;DR look the two last blocks of code

// To show the results in the page
var $log = $('#log');
var log = function(text) {
    $log.append(text+'<br/>');
};

// This returns a promise, and resolves it after the specified
// timeout. This behaves like a jQuery ajax call (but for the
// provided timeout)
var trigger = function(timeout) {
    log('<b>trigger</b> invoked');
    var deferred = $.Deferred();
    setTimeout(function() {
        log('<b>trigger</b> resolving promise');
        deferred.resolve('A','B');
    }, timeout);
    return deferred;
};

// This is the function we want to invoke
// The promise returns a and b - the extra params
// must be supplied in some way
var extraParams = function(extra1, extra2, a, b) {
    log('<b>extraParams</b> extra1:' + extra1);
    log('<b>extraParams</b> extra2:' + extra2);
    log('<b>extraParams</b> a:' + a);
    log('<b>extraParams</b> b:' + b);
};


// Doing it using indirection
trigger(500).then(function(a,b) {
  extraParams('extra1','extra2',a,b);
});

// Doing it using bind()
trigger(1200).then(
  extraParams.bind(this,'extra1','extra2')
);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="log">
</div>