Javascript 将附加参数传递给JSONP回调

Javascript 将附加参数传递给JSONP回调,javascript,jsonp,Javascript,Jsonp,对于我的一个项目,我需要使用JSONP对(远程)API进行多次调用,以处理API响应。所有调用都使用相同的回调函数。所有调用都是使用JavaScript在客户端动态生成的 问题如下:如何向该回调函数传递附加参数,以便告诉函数我使用的请求参数。因此,例如,在下面的示例中,我需要myCallback函数来了解id=123。 有没有什么方法可以实现这一点,而不必为我的每个调用创建单独的回调函数?最好使用普通的JavaScript解决方案 编辑: 在第一次评论和回答之后,出现了以下几点: 我无法

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

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


有没有什么方法可以实现这一点,而不必为我的每个调用创建单独的回调函数?最好使用普通的JavaScript解决方案

编辑

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

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

您的选择如下:

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

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

    假设为JSONP生成标记的函数如下所示(替换您现在使用的任何函数):

    然后,您可以在它之外使用另一个函数来执行此操作:

    // 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
    });
    

    既然我似乎不能评论,我必须写一个答案。我已经按照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数组中删除服务器的响应。因此,我只是提取数据并使用可用参数调用回调。这里的另一个区别是,我重复使用回调名称,我可能会使用计数器将其更改为完全唯一的名称


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

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

    (‘optA’)

    (‘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
            }
        }
    }
    
    有一个更简单的方法。 将参数附加到url的“?”之后。并在回调函数中访问它,如下所示

    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中追加参数。我在这里展示了一个快速脏的解决方案。

    您能让服务器返回id作为响应的一部分吗?服务器知道这一点,所以它可以为您将其放入响应代码中。您正在做需要做的事情。其余的由远程主机来识别您的参数。可能是的。。。。jQuery将使这变得非常简单,但如果您不想包含它,我可以理解。@jfriend00我无法控制远程服务器,因此没有任何更改代码动态生成JSONP调用?还是静态地包含在页面中?如果它是由代码动态生成的,则有更多的选项。这就是我心目中的后备计划。然而,这意味着创建(尽管是动态的)多个回调函数,这是我想要避免的。@Sirko-除非您能够保证一次只能有一个这种类型的JSONP请求,否则您必须执行类似的操作以将请求的状态与返回相匹配。根据定义,JSONP是相当愚蠢的。它所做的只是调用一个全局函数。而且,您已经拒绝让服务器为您解决此问题。因此,您必须将id存储在可访问的位置。如果要将正确的ID与正确的函数调用唯一地匹配,并且一次可以有多个函数调用,则每个函数调用必须是全局唯一的。@Sirko-如果一次只有一个JSONP调用(您可以保证这一点),然后将ID值存储在一个全局变量中,并从回调中检索它。这是一种脆弱的方法,因为当其他人不小心在同一时间执行两个JSONP调用时,代码中的细微变化很容易破坏它,而在此时解决问题将是一团混乱。仅供参考,我知道YUI做了一些事情
    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
     }