jQuery将更多参数传递给回调


255

有没有办法将更多数据传递到jQuery中的回调函数中?

我有两个函数$.post,例如,我希望回调到,以传递AJAX调用的结果数据以及一些自定义参数

function clicked() {
    var myDiv = $("#my-div");
    // ERROR: Says data not defined
    $.post("someurl.php",someData,doSomething(data, myDiv),"json"); 
    // ERROR: Would pass in myDiv as curData (wrong)
    $.post("someurl.php",someData,doSomething(data, myDiv),"json"); 
}

function doSomething(curData, curDiv) {

}

我希望能够将自己的参数以及AJAX调用返回的结果传递给回调。


14
值得一提的是,自版本1.4(jquery14.com/day-01/jquery-14)开始,jQuery.ajax()就有了上下文设置,请参见此处的用法示例:stackoverflow.com/questions/5097191/ajax-context-选项/…
russau 2011年

我解决了AJAX完成后返回数据的问题,然后执行了某些操作。
Onaiggac

Answers:


340

解决方案是通过闭包绑定变量。


作为一个更基本的示例,这是一个示例函数,该函数接收并调用一个回调函数,以及一个示例回调函数:

function callbackReceiver(callback) {
    callback("Hello World");
}

function callback(value1, value2) {
    console.log(value1, value2);
}

这将调用回调并提供一个参数。现在,您想提供一个附加参数,因此您可以将回调包装在闭包中。

callbackReceiver(callback);     // "Hello World", undefined
callbackReceiver(function(value) {
    callback(value, "Foo Bar"); // "Hello World", "Foo Bar"
});

或者,更简单地使用ES6箭头函数

callbackReceiver(value => callback(value, "Foo Bar")); // "Hello World", "Foo Bar"

对于您的特定示例,我没有.post在jQuery中使用过该函数,但是对文档的快速扫描显示,回调应该是具有以下签名的函数指针

function callBack(data, textStatus, jqXHR) {};

因此,我认为解决方案如下:

var doSomething = function(extraStuff) {
    return function(data, textStatus, jqXHR) {
        // do something with extraStuff
    };
};

var clicked = function() {
    var extraStuff = {
        myParam1: 'foo',
        myParam2: 'bar'
    }; // an object / whatever extra params you wish to pass.

    $.post("someurl.php", someData, doSomething(extraStuff), "json");
};

怎么了?

在最后一行中,doSomething(extraStuff)调用,并且调用的结果是一个函数指针

因为extraStuff作为参数传递给doSomething它,所以它在doSomething函数的范围之内。

extraStuff在返回的匿名内部函数中引用了when ,doSomething并通过闭包将其绑定到外部函数的extraStuff参数上。即使doSomething返回后也是如此。

我没有测试上面的内容,但是在过去的24小时中我编写了非常相似的代码,并且可以按照我的描述进行工作。

当然,根据个人喜好/编码标准,您可以传递多个变量而不是单个“ extraStuff”对象。


'var doSomething ='的目的是什么?与仅将doSomething声明为函数(即function doSomething(...){})有什么区别
Dave Neeley 2010年

7
这不是真的。不同的作用域规则适用于这两个函数声明。行为取决于JS运行时(读取浏览器)而有很大不同。另外,尝试比较Firebug中stacktrace / breakpoint中显示的函数名称。
Ihor Kaharlichenko,2011年

1
伊霍尔:关于两种声明样式之间的区别,您绝对正确。一个很好的解释是在这里:stackoverflow.com/questions/336859/...
bradhouse

2
由于示例的特殊性,对于尝试将其应用于更一般性问题的用户而言,这可能有点困难。我添加了一个简化的示例,使它易于理解,并添加了一个箭头函数示例,以防止此问题作为新发布的拟议副本的副本被关闭。如果您觉得我的编辑偏离了答案的原意或有其他不适当的地方,请随时将其回滚。

4
此答案的修订版4正在meta上
bjb568

82

使用时doSomething(data, myDiv),您实际上是在调用该函数,而不对其进行引用。

您可以doStomething直接传递函数,但必须确保其具有正确的签名。

如果要保持doSomething的状态,可以将其调用包装在匿名函数中。

function clicked() {
    var myDiv = $("#my-div");
    $.post("someurl.php",someData, function(data){ 
      doSomething(data, myDiv)
    },"json"); 
}

function doSomething(curData, curDiv) {
    ...
}

在匿名函数代码内部,您可以使用封闭范围中定义的变量。这就是Javascript作用域的工作方式。


9
为了清楚起见,这是IMO的最佳解决方案。return function(...){...}功能内没有其他doSomething功能。我发现了同样的概念的另一个明显的例子在这里:theelitist.net/...
威廉·丹尼斯

4
我认为这是有问题的。如果您的额外数据(在本例中为myDiv)在触发回调之前发生更改,则您将获得新值而不是旧值!就我而言,我正在对数组中的项目触发ajax调用,并且在执行第一个success()调用时,它认为它在第一个项目成功时就在最后一个项目上成功了!布拉德豪斯的答案对我有用。
克里斯

@Chris是的,可以在Javascript中更改捕获的变量。如果您不希望出现这种情况,则需要创建一个显式函数来捕获值。最常用的惯用法是(function(myDiv){ ... })(myDiv)捕获变量的自执行函数myDiv。这在@bradhouse答案中隐式完成。
文森特·罗伯特

如果您多次调用此ajax,则此方法将创建n个不同的函数,并将它们传递给成功回调。就性能而言,这是不好的。避免使用@zeroasterisk的答案是好的。
耶尔马兹

我同意@WilliamDenniss,恕我直言,这是最好,简单,清晰的解决方案
sebasira

52

实际上,它比每个人都听起来容易得多……尤其是如果您使用$.ajax({})基本语法而不是辅助函数之一。

key: value设置ajax请求时,就像在任何对象上一样传递对(因为$(this)尚未更改上下文,它仍然是上面的绑定调用的触发器)

<script type="text/javascript">
$(".qty input").bind("keypress change", function() {
    $.ajax({
        url: "/order_items/change/"+$(this).attr("data-order-item-id")+"/qty:"+$(this).val()+"/returnas.json",
        type: "POST",
        dataType: "json",
        qty_input: $(this),
        anything_else_i_want_to_pass_in: "foo",
        success: function(json_data, textStatus, jqXHR) {
            /* here is the input, which triggered this AJAX request */
            console.log(this.qty_input);
            /* here is any other parameter you set when initializing the ajax method */
            console.log(this.anything_else_i_want_to_pass_in);
        }
    });
});
</script>

这比设置var更好的原因之一是var是全局的,因此是可重写的……如果您有2个可以触发ajax调用的东西,理论上您可以比ajax调用响应更快地触发它们,并且您将把第二个呼叫的值传递给第一个。上面使用这种方法不会发生(而且使用起来也很简单)。


3
这正是我想要的。我不知道何时将dataType指定为json,它会自动为您解析响应。很好(:
Rooster

1
听起来是传递额外参数以回调给我的最佳方法。如果有人看到这种方法的缺点,我会感兴趣吗?最简单,最优雅。谢谢!
Jan Zyka

var是全局的,因此是可重写的 ”。不是在函数中声明它,而是比上面的解决方案更具可读性。使用闭包是一种更清洁的方法-在这里查看我的答案:stackoverflow.com/a/18570951/885464
Lorenzo Polidori

5
@LorenzoPolidori我不同意,我发现附加参数方法更具可读性。
2014年

2
这绝对是太棒了。我怎么从来没有见过这个。我不需要closure我只需要它工作,这绝对是王牌,干净,简单且不具有全局性。
Piotr Kula 2015年

21

在当今世界,还有另一个更干净的答案,该答案来自另一个Stack Overflow答案:

function clicked()
{
    var myDiv = $( "#my-div" );

    $.post( "someurl.php", {"someData": someData}, $.proxy(doSomething, myDiv), "json" );
}

function doSomething( data )
{
    // this will be equal to myDiv now. Thanks to jQuery.proxy().
    var $myDiv = this;

    // doing stuff.
    ...
}

这是原始的问题和答案: jQuery HOW TO?将其他参数传递给$ .ajax调用的成功回调?


8

您也可以尝试以下操作:

function clicked() {

    var myDiv = $("#my-div");

    $.post("someurl.php",someData,function(data){
        doSomething(data, myDiv);
    },"json"); 
}

function doSomething(curData, curDiv) {

}

5

您可以使用JavaScript的闭包:

function wrapper( var1, var2,....) // put here your variables
{
  return function( data, status)
  {
     //Handle here results of call
  }
};

以及何时可以:

$.post("someurl.php",data,wrapper(var1, var2, etc...),"html");

3

我在上一篇帖子中犯了一个错误。这是如何在回调函数中传递附加参数的有效示例:

function custom_func(p1,p2) {
    $.post(AJAX_FILE_PATH,{op:'dosomething',p1:p1},
        function(data){
            return function(){
                alert(data);
                alert(p2);
            }(data,p2)
        }
    );
    return false;
}

1
您应该编辑原始答案,或者在添加新答案之前将其删除。
Blazemonger,2011年

3

让我们变得简单!:)

$.ajax({
    url: myUrl,
    context: $this, // $this == Current $element
    success: function(data) {
        $.proxy(publicMethods.update, this)(data); // this == Current $element
    }
});

2

使用.ajax()jQuery API和闭包向异步函数传递附加参数来发送异步请求的更通用的解决方案:

function sendRequest(method, url, content, callback) {
    // additional data for the callback
    var request = {
        method: method,
        url: url
    };

    $.ajax({
        type: method,
        url: url,
        data: content
     }).done(function(data, status, xhr) {
        if (callback) callback(xhr.status, data, request);
     }).fail(function(xhr, status) {
        if (callback) callback(xhr.status, xhr.response, request);
     });
};

1

对于我和刚接触过Javascript的其他新手来说,
我认为Closeure Solution有点太混乱了。

虽然我发现了这一点,但您可以使用jquery轻松地将所需数量的参数传递给每个ajax回调。

这是两个更简单的解决方案

@zeroasterisk在上面提到的第一个示例:

var $items = $('.some_class');
$.each($items, function(key, item){
    var url = 'http://request_with_params' + $(item).html();
    $.ajax({
        selfDom     : $(item),
        selfData    : 'here is my self defined data',

        url         : url,
        dataType    : 'json',
        success     : function(data, code, jqXHR){
            // in $.ajax callbacks, 
            // [this] keyword references to the options you gived to $.ajax
            // if you had not specified the context of $.ajax callbacks.
            // see http://api.jquery.com/jquery.ajax/#jQuery-ajax-settings context
            var $item = this.selfDom;
            var selfdata = this.selfData;
            $item.html( selfdata );
            ...
        } 
    });
});

第二,通过将自定义数据添加到XHR object 整个ajax-request-response生命周期中存在的自定义数据中来。

var $items = $('.some_class');
$.each($items, function(key, item){
    var url = 'http://request_with_params' + $(item).html();
    $.ajax({
        url         : url,
        dataType    : 'json',
        beforeSend  : function(XHR) {
            // 为了便于回调,把当前的 jquery对象集存入本次 XHR
            XHR.selfDom = $(item);
            XHR.selfData = 'here is my self defined data';
        },
        success     : function(data, code, jqXHR){
            // jqXHR is a superset of the browser's native XHR object
            var $item = jqXHR.selfDom;
            var selfdata = jqXHR.selfData;
            $item.html( selfdata );
            ...
        } 
    });
});

如您所见,这两种解决方案都有一个缺点:与每次编写相比,您每次都需要编写更多的代码:

$.get/post (url, data, successHandler);

了解更多有关$ .ajax的信息:http : //api.jquery.com/jquery.ajax/


1

如果有人仍然来这里,这是我的看法:

$('.selector').click(myCallbackFunction.bind({var1: 'hello', var2: 'world'}));

function myCallbackFunction(event) {
    var passedArg1 = this.var1,
        passedArg2 = this.var2
}

绑定到回调函数后,此处将发生什么,它将在函数中以形式提供this

这个想法来自React如何使用bind功能。


1
$(document).on('click','[action=register]',function(){
    registerSocket(registerJSON(),registerDone,second($(this)));
});

function registerSocket(dataFn,doneFn,second){
                 $.ajax({
                       type:'POST',
                       url: "http://localhost:8080/store/public/register",
                       contentType: "application/json; charset=utf-8",
                       dataType: "json",
                       data:dataFn
                 }).done ([doneFn,second])
                   .fail(function(err){
                            console.log("AJAX failed: " + JSON.stringify(err, null, 2));
                        });
}

function registerDone(data){
    console.log(JSON.stringify(data));
}
function second(element){
    console.log(element);
}

次要方式:

function socketWithParam(url,dataFn,doneFn,param){
  $.ajax({
    type:'POST',
    url:url,
    contentType: "application/json; charset=utf-8",
    headers: { 'Authorization': 'Bearer '+localStorage.getItem('jwt')},
    data:dataFn
    }).done(function(data){
      doneFn(data,param);
    })
    .fail(function(err,status,xhr){
    console.log("AJAX failed: " + JSON.stringify(err, null, 2));
    });
}

$(document).on('click','[order-btn]',function(){
  socketWithParam(url,fakeDataFn(),orderDetailDone,secondParam);
});

function orderDetailDone(data,param){
  -- to do something --
}

0

实际上,您的代码无法正常工作,因为您在编写时:

$.post("someurl.php",someData,doSomething(data, myDiv),"json"); 

您将函数调用作为第三个参数,而不是函数引用


0

作为b01答案的附录,$.proxy常常使用的第二个参数来保留this引用。传递给的其他参数$.proxy部分应用于函数,并用数据预填充。请注意,$.post传递给回调的所有参数都将在末尾应用,因此doSomething应在其参数列表的末尾使用这些参数:

function clicked() {
    var myDiv = $("#my-div");
    var callback = $.proxy(doSomething, this, myDiv);
    $.post("someurl.php",someData,callback,"json"); 
}

function doSomething(curDiv, curData) {
    //"this" still refers to the same "this" as clicked()
    var serverResponse = curData;
}

这种方法还允许将多个参数绑定到回调:

function clicked() {
    var myDiv = $("#my-div");
    var mySpan = $("#my-span");
    var isActive = true;
    var callback = $.proxy(doSomething, this, myDiv, mySpan, isActive);
    $.post("someurl.php",someData,callback,"json"); 
}

function doSomething(curDiv, curSpan, curIsActive, curData) {
    //"this" still refers to the same "this" as clicked()
    var serverResponse = curData;
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.