封装 JSONP
随机生成函数名是为了确保唯一性。因为 JSONP 的回调实际上是创建了一个临时的函数供加载的 js 调用。如果回调函数不是随机的,那在连续 JSONP 请求时,后发出的请求回调函数会覆盖掉之前的,返回的数据会出问题。
1 2 3 4 5 6 7 8 9 10
| function getJSONP(url, callback) { if (!url) { return; } // 声明数组来随机生成函数名 var a = ["a", "b", "c", "d", "e", "f", "g", "h", "i"]; var r1 = Math.floor(Math.random() * a.length); var r2 = Math.floor(Math.random() * a.length); var r3 = Math.floor(Math.random() * a.length); var name = "getJSONP" + a[r1] + a[r2] + a[r3]; //name上加的前缀可以任意取名
|
回调函数名传给服务器之后,这个回调函数名是要作为 getJSONP 函数的一个属性的,所以 cbname=‘getJSONP.’+name; 回调函数名前面拼接的一定得是‘getJSONP.’和 getJSONP 函数同命,表示获取 getJSONP 函数的属性。
1 2 3 4 5 6 7 8 9
| var cbname = "getJSONP." + name; // 判断url地址是否含有? if (url.indexOf("?") === -1) { url += "?jsonp=" + cbname; } else { url += "&jsonp=" + cbname; } // 动态创建script标签 var script = document.createElement("script");
|
核心,定义被脚本执行的回调函数
getJSONP 函数的精华在于定义被脚本执行的回调函数,定义完之后要被销毁。
函数内不要进行 if 判断,而是用 try catch 来尝试执行。
每跨域一次,都要生成一个回调函数,跨域多了生成的回调函数也多,会污染环境,所以在跨域执行完之后要把回调函数删掉。所以用 try catch 会更适合。
1 2 3 4 5 6 7 8 9 10 11 12
| getJSONP[name] = function () { try { callback && callback(data); //两个必须都为真,才为真,若是第一个为假的话,第二个就不执行了,直接返回。 } catch (e) { // } finally { // finally 语句在 try 和 catch 之后无论有无异常都会执行。这里不管函数有没有执行成功,都要删除回调函数和script标签,避免污染环境。 // 注意: catch 和 finally 语句在语法上都是可选的,但你在使用 try 语句时必须至少使用一个。 //最后删除该函数及script标签 delete getJSONP[name]; script.parentNode.removeChild(script); } }
|
1 2 3 4
| // 定义script的src script.src = url; document.getElementsByTagName("head")[0].appendChild(script); }
|
最后跨域调用尝试
1 2 3
| getJSONP("http://class.imooc.com/api/jsonp", function (data) { console.log(data); });
|