javascript 将附加参数传递给 JSONP 回调
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9570768/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Pass additional parameter to a JSONP callback
提问by Sirko
For a project of mine I need to do multiple calls to a (remote) API using JSONP for processing the API response. All calls use the same callback function. All the calls are generated dynamically on the client's side using JavaScript.
对于我的一个项目,我需要使用 JSONP 对(远程)API 进行多次调用以处理 API 响应。所有调用都使用相同的回调函数。所有调用都是在客户端使用 JavaScript 动态生成的。
The problem is as follows: How do I pass additional parameters to that callback function in order to tell the function about the request parameters I used. So, e.g., in the following example, I need the myCallback
function to know about id=123
.
问题如下:如何将附加参数传递给该回调函数,以便将我使用的请求参数告知该函数。因此,例如,在以下示例中,我需要该myCallback
函数来了解id=123
.
<script src="http://remote.host.com/api?id=123&jsonp=myCallback"></script>
Is there any way to achieve this without having to create a separate callback function for each of my calls? A vanilla JavaScript solution is preferred.
有什么方法可以实现这一点,而不必为我的每个调用创建单独的回调函数?首选香草 JavaScript 解决方案。
EDIT:
编辑:
After the first comments and answers the following points came up:
在第一次评论和回答之后,出现了以下几点:
- I do not have any control over the remote server. So adding the parameter to the response is not an option.
- I fire up multiple request concurrently, so any variable to store my parameters does not solve the problem.
- I know, that I can create multiple callbacks on the fly and assign them. But the question is, whether I can avoid this somehow. This would be my fallback plan, if no other solutions pop up.
- 我对远程服务器没有任何控制权。因此,将参数添加到响应中不是一种选择。
- 我同时启动了多个请求,因此任何存储参数的变量都不能解决问题。
- 我知道,我可以即时创建多个回调并分配它们。但问题是,我是否可以以某种方式避免这种情况。如果没有其他解决方案出现,这将是我的后备计划。
采纳答案by jfriend00
Your options are as follows:
您的选择如下:
- Have the server put the ID into the response. This is the cleanest, but often you cannot change the server code.
- If you can guarantee that there is never more than one JSONP call involving the ID inflight at once, then you can just stuff the ID value into a global variable and when the callback is called, fetch the id value from the global variable. This is simple, but brittle because if there are every more than one JSONP call involving the ID in process at the same time, they will step on each other and something will not work.
- Generate a unique function name for each JSONP call and use a function closure associated with that function name to connect the id to the callback.
- 让服务器将 ID 放入响应中。这是最干净的,但通常您无法更改服务器代码。
- 如果您可以保证一次涉及 ID inflight 的 JSONP 调用不会超过一个,那么您可以将 ID 值填充到一个全局变量中,并在调用回调时从全局变量中获取 id 值。这很简单,但很脆弱,因为如果同时有一个以上的 JSONP 调用涉及正在处理的 ID,它们将相互影响,并且某些事情将不起作用。
- 为每个 JSONP 调用生成唯一的函数名称,并使用与该函数名称关联的函数闭包将 id 连接到回调。
Here's an example of the third option.
这是第三个选项的示例。
You can use a closure to keep track of the variable for you, but since you can have multiple JSON calls in flight at the same time, you have to use a dynamically generated globally accessible function name that is unique for each successive JSONP call. It can work like this:
您可以使用闭包来为您跟踪变量,但由于您可以同时进行多个 JSON 调用,因此您必须使用动态生成的全局可访问函数名称,该名称对于每个连续的 JSONP 调用都是唯一的。它可以像这样工作:
Suppose your function that generate the tag for the JSONP is something like this (you substitute whatever you're using now):
假设您为 JSONP 生成标签的函数是这样的(您可以替换现在使用的任何内容):
function doJSONP(url, callbackFuncName) {
var fullURL = url + "&" + callbackFuncName;
// generate the script tag here
}
Then, you could have another function outside of it that does this:
然后,您可以在它之外使用另一个函数来执行此操作:
// 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);
}
Your main code would call getDataForId()
and the callback passed to it would be passed the id value like this followed by whatever other arguments the JSONP had on the function:
您的主代码将调用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
});
回答by user3805007
There's a easier way. Append the parameter to your url after '?'. And access it in the callback function as follows.
有一个更简单的方法。在 '?' 之后将参数附加到您的 url。并在回调函数中访问它,如下所示。
var url = "yourURL";
url += "?"+"yourparameter";
$.jsonp({
url: url,
cache: true,
callbackParameter: "callback",
callback: "cb",
success: onreceive,
error: function () {
console.log("data error");
}
});
And the call back function as follows
和回调函数如下
function onreceive(response,temp,k){
var data = k.url.split("?");
alert(data[1]); //gives out your parameter
}
Note: You can append the parameter in a better way in the URL if you already have other parameters in the URL. I have shown a quick dirty solution here.
注意:如果 URL 中已有其他参数,则可以在 URL 中以更好的方式附加参数。我在这里展示了一个快速的肮脏解决方案。
回答by stackmagic
Since it seems I can't comment, I have to write an answer. I've followed the instructions by jfriend00 for my case but did not receive the actual response from the server in my callback. What I ended up doing was this:
由于我似乎无法发表评论,因此我必须写一个答案。我已经按照 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);
}
Essentially, I compacted goJSONP and getDataForUrl into 1 function which writes the script tag (and removes it later) as well as not use the "unshift" function since that seemed to remove the server's response from the args array. So I just extract the data and call my callback with the arguments available. Another difference here is, I re-use the callback names, I might change that to completely unique names with a counter.
从本质上讲,我将 goJSONP 和 getDataForUrl 压缩为 1 个函数,该函数写入脚本标记(并稍后将其删除)并且不使用“unshift”函数,因为这似乎从 args 数组中删除了服务器的响应。所以我只是提取数据并使用可用参数调用我的回调。这里的另一个区别是,我重用了回调名称,我可能会使用计数器将其更改为完全唯一的名称。
What's missing as of now is timeout handling. I'll probably start a timer and check for existence of the callback function. If it exists it hasn't removed itself so it's a timeout and I can act accordingly.
目前缺少的是超时处理。我可能会启动一个计时器并检查回调函数是否存在。如果它存在,它不会自行删除,所以它是超时,我可以采取相应的行动。
回答by JeB
This is a year old now, but I think jfriend00 was on the right track, although it's simpler than all that - use a closure still, just, when specifying the callback add the param:
这是一岁了,但我认为 jfriend00 走在正确的轨道上,虽然它比所有这些都简单 - 仍然使用闭包,只是在指定回调时添加参数:
http://url.to.some.service?callback=myFunc('optA')
http://url.to.some.service?callback=myFunc('optA')
http://url.to.some.service?callback=myFunc('optB')
http://url.to.some.service?callback=myFunc('optB')
Then use a closure to pass it through:
然后使用一个闭包来传递它:
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
}
}
}