将其他参数传递给JSONP回调

Sir*_*rko 11 javascript jsonp

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

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

<script src="http://remote.host.com/api?id=123&jsonp=myCallback"></script>
Run Code Online (Sandbox Code Playgroud)

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

编辑:

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

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

jfr*_*d00 10

您的选择如下:

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

这是第三个选项的示例.

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

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

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

然后,您可以在其外部执行另一个功能:

// 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);
}
Run Code Online (Sandbox Code Playgroud)

您的主代码将调用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
});
Run Code Online (Sandbox Code Playgroud)