jQuery批量JSONP请求出现ReferenceError及响应异常问题求助
jsonpCallback导致随机失败及报错的原因分析 我来帮你拆解下这个问题的核心根源,以及对应的解决办法:
问题本质:共用全局回调函数的冲突
JSONP的工作逻辑是通过动态插入<script>标签实现跨域请求,服务端返回的是一段调用指定回调函数的JS代码(比如parseResponse({...}))。当你把所有请求的jsonpCallback都硬编码为parseResponse时,会触发两个关键问题:
随机失败的原因:jQuery发起每个JSONP请求时,都会在全局作用域注册
parseResponse这个函数。但循环批量请求时,后一个请求会直接覆盖前一个请求注册的parseResponse函数。而请求的响应是异步返回的——如果某个请求的响应回来时,parseResponse已经被后面的请求替换成新回调(或者已经被jQuery清理),这个请求就会失败。谁的响应先赶在回调被覆盖前返回,谁就能成功,这就是成功请求随机的核心原因。单次报错的原因:每个JSONP请求完成后,jQuery会自动清理对应的全局回调函数(同时移除插入的
<script>标签)。当最后一个请求完成后,parseResponse会被彻底清理,但如果有某个请求的响应在这之后才返回,就会找不到parseResponse函数,触发Uncaught ReferenceError。而因为最后只有一个回调被清理,所以只会触发一次这个错误。
解决办法
方案1:让jQuery自动生成唯一回调名(推荐)
这是最省心的方式,jQuery默认会为每个JSONP请求生成唯一的回调函数名(比如jQuery21101234567890_1234567890),完全避免冲突。你只需要删除jsonpCallback : 'parseResponse'这一行即可:
var url = "http://jsfiddle.net/echo/jsonp/"; aj('single'); for (var i = 0; i < 8; i++) { aj('loop' + i); } function aj(s) { $.ajax({ url : url, dataType : 'jsonp' }).fail(function(jqXHR) { console.log(s + ' - F'); }).done(function(res) { console.log(s + ' - S'); }); }
方案2:手动生成唯一回调名(若必须指定回调前缀)
如果因为特定需求不能用自动生成的名字,那就要为每个请求创建唯一的回调函数名,比如结合请求标识s来生成,同时记得在请求完成(成功/失败)后清理全局函数,避免作用域污染:
var url = "http://jsfiddle.net/echo/jsonp/"; aj('single'); for (var i = 0; i < 8; i++) { aj('loop' + i); } function aj(s) { // 生成唯一的回调函数名 var uniqueCallback = 'parseResponse_' + s; // 注册全局回调 window[uniqueCallback] = function(res) { console.log(s + ' - S'); // 清理全局函数 delete window[uniqueCallback]; }; $.ajax({ url : url, dataType : 'jsonp', jsonpCallback : uniqueCallback }).fail(function(jqXHR) { console.log(s + ' - F'); // 失败也要清理 delete window[uniqueCallback]; }); }
内容的提问来源于stack exchange,提问作者Emeric.Lee

