将其他参数传递给JSONP回调

时间:2012-03-05 17:03:15

标签: javascript jsonp

对于我的项目,我需要使用JSONP对(远程)API进行多次调用以处理API响应。所有调用都使用相同的回调函数。所有调用都是使用JavaScript在客户端动态生成的。

问题如下:如何将其他参数传递给该回调函数,以便告诉函数我使用的请求参数。因此,例如,在以下示例中,我需要myCallback函数来了解id=123

<script src="http://remote.host.com/api?id=123&jsonp=myCallback"></script>

有没有办法实现这一点,而无需为每个调用创建单独的回调函数?一个vanilla JavaScript解决方案是首选。

修改

在第一个评论和答案之后,出现了以下几点:

  • 我对远程服务器没有任何控制权。因此,不能选择将参数添加到响应中。
  • 我同时启动多个请求,因此存储我的参数的任何变量都无法解决问题。
  • 我知道,我可以动态创建多个回调并分配它们。但问题是,我能否以某种方式避免这种情况。如果没有其他解决方案弹出,这将是我的后备计划。

4 个答案:

答案 0 :(得分:10)

您的选择如下:

  1. 让服务器将ID放入响应中。这是最干净的,但通常无法更改服务器代码。
  2. 如果您可以保证永远不会有多个JSONP调用涉及ID inflight,那么您可以将ID值填充到全局变量中,并且在调用回调时,从全局变量中获取id值。这很简单,但是很脆弱,因为如果同时有多个JSONP调用涉及到进程中的ID,它们将相互踩踏,并且某些东西将无法工作。
  3. 为每个JSONP调用生成一个唯一的函数名称,并使用与该函数名称关联的函数闭包将id连接到回调。
  4. 以下是第三个选项的示例。

    您可以使用闭包来跟踪变量,但由于您可以同时在飞行中进行多个JSON调用,因此您必须使用动态生成的全局可访问函数名称,该函数名称对于每个连续的JSONP都是唯一的呼叫。它可以像这样工作:

    假设您为JSONP生成标记的函数是这样的(您可以替换现在正在使用的任何内容):

    function doJSONP(url, callbackFuncName) {
       var fullURL = url + "&" + callbackFuncName;
       // generate the script tag here
    }
    

    然后,你可以在它之外有另一个功能:

    // global var
    var jsonpCallbacks = {cntr: 0};
    
    
    function getDataForId(url, id, fn) {
        // create a globally unique function name
        var name = "fn" + jsonpCallbacks.cntr++;
    
        // put that function in a globally accessible place for JSONP to call
        jsonpCallbacks[name] = function() {
            // upon success, remove the name
            delete jsonpCallbacks[name];
            // now call the desired callback internally and pass it the id
            var args = Array.prototype.slice.call(arguments);
            args.unshift(id);
            fn.apply(this, args);
        }
    
        doJSONP(url, "jsonpCallbacks." + name);
    }
    

    你的主代码会调用getDataForId(),传递给它的回调将传递id值,然后是JSONP对函数的其他参数:

    getDataForId(123, "http://remote.host.com/api?id=123", function(id, /* other args here*/) {
        // you can process the returned data here with id available as the argument
    });
    

答案 1 :(得分:1)

有一种更简单的方法。 在“?”之后将参数附加到您的网址。并在回调函数中访问它,如下所示。

var url = "yourURL";
    url += "?"+"yourparameter";
    $.jsonp({
        url: url,
        cache: true,
        callbackParameter: "callback",
        callback: "cb",
        success: onreceive,
        error: function () {
            console.log("data error");
        }
    });

回调功能如下

function onreceive(response,temp,k){
  var data = k.url.split("?");
  alert(data[1]);   //gives out your parameter
 }

注意:如果URL中已有其他参数,则可以在URL中以更好的方式附加参数。我在这里展示了一个快速的解决方案。

答案 2 :(得分:0)

由于我似乎无法评论,我必须写一个答案。我已按照jfriend00的说明处理了我的情况,但在我的回调中没有收到服务器的实际响应。我最终做的是:

var callbacks = {};

function doJsonCallWithExtraParams(url, id, renderCallBack) {
    var safeId = id.replace(/[\.\-]/g, "_");
    url = url + "?callback=callbacks." + safeId;
    var s = document.createElement("script");
    s.setAttribute("type", "text/javascript");
    s.setAttribute("src", url);

    callbacks[safeId] = function() {
        delete callbacks[safeId];
        var data = arguments[0];
        var node = document.getElementById(id);
        if (data && data.status == "200" && data.value) {
            renderCallBack(data, node);
        }
        else {
            data.value = "(error)";
            renderCallBack(data, node);
        }

        document.body.removeChild(s);
    };

    document.body.appendChild(s);
}

基本上,我将goJSONP和getDataForUrl压缩为1个函数,该函数编写脚本标记(并在以后删除它)以及不使用“unshift”函数,因为这似乎从args数组中删除了服务器的响应。所以我只是提取数据并使用可用的参数调用我的回调。这里的另一个不同之处是,我重新使用回调名称,我可能会将其更改为带有计数器的完全唯一的名称。

现在缺少的是超时处理。我可能会启动一个计时器并检查是否存在回调函数。如果它存在,它没有自行删除,所以它是一个超时,我可以采取相应的行动。

答案 3 :(得分:-1)

现在已经有一年了,但我认为jfriend00在正确的轨道上,虽然它比所有更简单 - 使用闭包仍然,只是,在指定回调时添加参数:

http://url.to.some.service?callback=myFunc( 'OPTA')

http://url.to.some.service?callback=myFunc( 'optB')

然后使用闭包传递它:

function myFunc (opt) {
    var myOpt = opt; // will be optA or optB

    return function (data) {
        if (opt == 'optA') {
            // do something with the data
        }
        else if (opt == 'optB') {
            // do something else with the data
        }
    }
}