在一個(gè)head標(biāo)簽中我們可以這么寫(xiě)
<script>
var callback = function(data){
console.log(data);
}
callback({name:'王柯智',age:'18'})
// 在控制臺(tái)打印出 {name:'王柯智',age:'18'}
</script>
我們定義了一個(gè)函數(shù),然后我們又調(diào)用了這個(gè)函數(shù),接下來(lái)我們把調(diào)用函數(shù)這句話(huà)(callback({name:'王柯智',age:'18'}))放在同級(jí)目錄下的另外一個(gè)JS文件叫做jsonp.js文件中,接下來(lái)我們的head標(biāo)簽就可以這么寫(xiě)
<script>
var callback = function(data){
console.log(data);
}
</script>
<script src='./jsop.js'>
</script>
以上代碼跟第一次我們寫(xiě)的代碼效果一模一樣。但是我們是從引入外部的JS來(lái)調(diào)用我們自己定義的函數(shù)。
如果把這個(gè)外部js放在服務(wù)器上的話(huà),我們的script標(biāo)簽可以會(huì)變成這種形式:
<script src='http://xxx.com/jsonp.js'>
</script>
然后我們?cè)诜?wù)器的jsonp.js文件里可以把服務(wù)器的數(shù)據(jù)拿到JS當(dāng)中,也就是說(shuō)這里的JS是這么寫(xiě)的
callback({key1:'value',key2:'value2'})
由于我們可能會(huì)多次調(diào)用callback函數(shù),為了把每次調(diào)用的函數(shù)和函數(shù)調(diào)用后得到的結(jié)果對(duì)應(yīng)起來(lái),通常我們會(huì)為這個(gè)函數(shù)取一個(gè)隨機(jī)的名字,代碼實(shí)現(xiàn)如下:
var num = Math.floor(Math.random() * 100000) // num是一個(gè)1到10萬(wàn)隨機(jī)數(shù)
window.callbackName = 'callback_' + num; //給windou添加一個(gè)全局屬性callbackName
window[callbackName] = function(data){
console.log(data);
}
此時(shí)我們定義便有了一個(gè)callback便有了一個(gè)隨機(jī)的名字,但是問(wèn)題來(lái)了,由于我們定義的函數(shù)名是隨機(jī)的,我們自己都不知道如何調(diào)用,我們?cè)趺词狗?wù)器上的那個(gè)函數(shù)名變成我們的函數(shù)名呢?
JSONP給出了一個(gè)方法,即在你需要加載的js文件后面加上'?callback="你的函數(shù)名"',所以我們的script標(biāo)簽便需要這樣寫(xiě):
<script src='http://xxx.com/jsopn.js?callback='+callbackName>
這樣我們就能把服務(wù)器上的函數(shù)名callback改成我們這里定義的函數(shù)名了。
可是還有個(gè)問(wèn)題,我們使用了2個(gè)script標(biāo)簽,一般來(lái)說(shuō),第二個(gè)script我們需要他動(dòng)態(tài)加載,所以我們只需要使用一個(gè)scirpt標(biāo)簽:
<script>
var num = Math.floor(Math.random() * 100000) // num是一個(gè)1到10萬(wàn)隨機(jī)數(shù)
window.callbackName = 'callback_' + num; //給windou添加一個(gè)全局屬性callbackName
window[callbackName] = function(data){
console.log(data);
}
//定義我們自己的函數(shù),并給他賦予一個(gè)隨機(jī)的名字
var sc = document.create('script')
sc.src = 'http://xxx.com/jsopn.js?callback=' + callbackName;
sc.id = 'script_' + callbackName;
document.body.appendChild(sc);
// script標(biāo)簽只有添加到文檔當(dāng)中才會(huì)去請(qǐng)求資源。
document.getElementById(sc.id).remove();
//當(dāng)函數(shù)被調(diào)用以后得到了服務(wù)器端的數(shù)據(jù)便把script標(biāo)簽從文檔中移除.
</script>
以上便是JSONP的用法。
當(dāng)然,我們可以給callback不同的功能,比如上述代碼中我們callback的功能是打印出data,你也可以再寫(xiě)一個(gè)callback,比如里面的代碼是console.log('xxx')也是可以的,但是這樣的話(huà)你可能會(huì)重寫(xiě)一次上面的代碼,會(huì)顯得很麻煩,所以我們把JSONP封裝一下,變成下面這個(gè)樣子:
function jsonp(url,fn){
var num = Math.floor(Math.random() * 100000);
var callbackName = 'callback_' + num;
window[callbackName] = fn;
var sc = document.createElement('script');
sc.src = url + '?callback=' + callbackName;
sc.id = 'script_' + num;
document.body.appendChild(sc);
document.getElementById(sc.id).remove()
}
這樣,當(dāng)我們想用jsonp的方式獲取數(shù)據(jù)并且對(duì)數(shù)據(jù)進(jìn)行處理的話(huà)就可以直接運(yùn)行
jsonp('http://www.xxx.com/jsop.js',function(data){
console.log(data);
})
當(dāng)然,我們也推薦使用JQuery的封裝好的JSONP語(yǔ)法:
$.ajax({
url:'http://www.xxx.com/jsonp.js',
datatype:'jsonp',
success:function(data){
console.log(data);
}
}
)
不過(guò)需要注意的是,雖然JQ這里寫(xiě)的是$.ajax,但是JSONP并不是Ajax,這樣寫(xiě)只是為了方便而把Ajax和JSONP的功能封裝在了一起,你在瀏覽器下打開(kāi)開(kāi)發(fā)者工具可以看到j(luò)sop的請(qǐng)求類(lèi)型不是xhr。