摘要:但是當我們有多個請求,并且每個請求的處理都是不一樣的時候,這個變量將會被覆蓋。這是不行的,因此我們應該為每一次請求設置一個唯一且不會沖突的變量,因此增加一個生成名字的方法如下這時候我們會發現我們已經利用了一個類似于隨機的形式完成了多次請求。
文章首發于我的github及個人博客,github請看https://github.com/huruji/blo...,轉載請注明出處。
JSONP的原理就不細說了,就是利用script可以跨域的特點來實現跨域,首先我們考慮一個最簡單的jsonp,就是簡簡單單創建script標簽,
添加url的功能,如下:
function jsonp(url) { const script = document.createElement("script"); script.src = url; script.type = "text/javascript"; document.body.appendChild(script); }
此時我們使用服務端的代碼如下:
const http = require("http"); const data = {"data":"hello"}; const url = require("url"); const queryString = require("querystring"); http.createServer(function(req, res) { var params = url.parse(req.url); console.log(params); if(params.query && queryString.parse(params.query).callback) { console.log(1231232); const str = queryString.parse(params.query).callback + "(" + JSON.stringify(data) + ")"; return res.end(str) } res.end(JSON.stringify(data)); }).listen(5000);
這是我們調用jsonp,假設我們只是想要alert出返回的數據,如下:
function msg(res) { alert(res.data); } jsonp("http://localhost:5000?callback=msg");
這時候我們運行代碼可以發現已經正確彈出了相應的數據。
但是我們會發現這里的callback回調函數是一個全局的,這是不可取的,因此我們需要進行一些修改,將處理修改為一個局部的,我們可以將其作為一個回調函數來處理,如下:
function jsonp(url, callback) { window.jsonpCallback = callback; const script = document.createElement("script"); script.src = url + "?callback=jsonpCallback"; script.type = "text/javascript"; document.body.appendChild(script); } jsonp("http://localhost:5000", function(res) { alert(res.data); });
這時候我們會發現我們不再需要在url中聲明相應的callback了,但是我們還是會發現一個問題,就是我們將所有的callback都設置成了一個全局變量,這樣的原因是因為我們需要在數據請求完成之后調用這個方法,因此不得不設置為一個全局變量。但是當我們有多個請求,并且每個請求的處理都是不一樣的時候,這個變量將會被覆蓋。這是不行的,因此我們應該為每一次請求設置一個唯一且不會沖突的變量,因此增加一個生成callback名字的方法如下:
function generateJsonpCallback() { return `jsonpcallback_${Date.now()}_${Math.floor(Math.random() * 100000)}`; } function jsonp(url, callback) { const funcName = generateJsonpCallback(); window[funcName] = callback; const script = document.createElement("script"); script.src = `${url}?callback=${funcName}`; script.type = "text/javascript"; document.body.appendChild(script); } jsonp("http://localhost:5000", function(res) { alert(res.data); }); jsonp("http://localhost:5000", function(res) { const text = document.createTextNode(res.data); document.body.appendChild(text); });
這時候我們會發現我們已經利用了一個類似于隨機ID的形式完成了多次請求。
但是還是有一個問題大量的請求之后,window中會含有大量的全局變量,而且還有大量的script標簽,這顯然不是我們想要的,所以我們可以在請求完成之后刪除變量和script標簽。
function generateJsonpCallback() { return `jsonpcallback_${Date.now()}_${Math.floor(Math.random() * 100000)}`; } function removeScript(id) { document.body.removeChild(document.getElementById(id)); } function removeFunc(name) { delete window[name]; } function jsonp(url, timeout = 3000, callback) { const funcName = generateJsonpCallback(); window[funcName] = callback; const script = document.createElement("script"); script.src = `${url}?callback=${funcName}`; script.id = funcName; script.type = "text/javascript"; document.body.appendChild(script); setTimeout(() => { removeScript(funcName); removeFunc(funcName); }, timeout) } jsonp("http://localhost:5000", 3000, function(res) { alert(res.data); }); jsonp("http://localhost:5000", 3000, function(res) { const text = document.createTextNode(res.data); document.body.appendChild(text); });
我們通過將利用一個timeout時間定時為我們清除相應的script標簽和全局變量就可以了,這個定時時間的作用類似于ajax的timeout時間。
我們所有的內容都是使用es6的,那為什么不使用Promise來處理呢,還要使用煩人的回調,接下來那就來Promise化吧。
function jsonp(url, options = {timeout:3000}) { const timeout = options.timeout; return new Promise((resolve, reject) => { const funcName = generateJsonpCallback(); window[funcName] = (res) => { resolve(res); setTimeout(() => { removeScript(funcName); removeFunc(funcName); }, timeout) }; const script = document.createElement("script"); script.src = `${url}?callback=${funcName}`; script.id = funcName; script.type = "text/javascript"; document.body.appendChild(script); }) }
調用只需要如下就可以了
jsonp("http://localhost:5000").then((res) => alert(res.data)); jsonp("http://localhost:5000").then((res) => { const text = document.createTextNode(res.data); document.body.appendChild(text); });
到目前為止,一個較為完整的jsonp就實現了,但是我們還是會覺得少了一些什么,相信你已經看出來了,那就是錯誤處理。
迄今為止,并沒有測試過如果這個script標簽加載不成功如何處理,判斷資源加載失敗,顯然使用的是onerror事件,我們這就把他加上:
function jsonp(url, options = {timeout:3000}) { const timeout = options.timeout; let timeId; return new Promise((resolve, reject) => { const funcName = generateJsonpCallback(); window[funcName] = (res) => { resolve(res); timeId = setTimeout(() => { removeScript(funcName); removeFunc(funcName); }, timeout) }; const script = document.createElement("script"); script.src = `${url}?callback=${funcName}`; script.id = funcName; script.type = "text/javascript"; document.body.appendChild(script); script.onerror = () => { reject(new Error(`fetch ${url} failed`)); removeScript(funcName); removeFunc(funcName); if(timeId) clearTimeout(timeId); } }) }
我們可以測試一下,輸入一個不存在的url:
jsonp("http://localhost:7000").then((res) => alert(res.data));
可以發現這時正常處理錯誤了,可以在控制臺看到相應的url獲取失敗,至此,完工;
至此所有的代碼簡單封裝如下:
(function(global){ function generateJsonpCallback() { return `jsonpcallback_${Date.now()}_${Math.floor(Math.random() * 100000)}`; } function removeScript(id) { document.body.removeChild(document.getElementById(id)); } function removeFunc(name) { delete global[name]; } function jsonp(url, options = {timeout:3000}) { const timeout = options.timeout; let timeId; return new Promise((resolve, reject) => { const funcName = generateJsonpCallback(); global[funcName] = (res) => { resolve(res); timeId = setTimeout(() => { removeScript(funcName); removeFunc(funcName); }, timeout) }; const script = document.createElement("script"); script.src = `${url}?callback=${funcName}`; script.id = funcName; script.type = "text/javascript"; document.body.appendChild(script); script.onerror = () => { reject(new Error(`fetch ${url} failed`)); removeScript(funcName); removeFunc(funcName); if(timeId) clearTimeout(timeId); } }) } window.jsonp = jsonp; })(window);
測試代碼如下:
jsonp("http://localhost:5000").then((res) => alert(res.data)); jsonp("http://localhost:5000").then((res) => { const text = document.createTextNode(res.data); document.body.appendChild(text); }); jsonp("http://localhost:7000").then((res) => alert(res.data));
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/88769.html
摘要:它之后能夠被使用到很多場景中其他處理請求和響應的方式,甚至任何需要生成自己的響應的方式。總結到這里都講完了,其實沒什么難度,主要是自己項目中遇到了,但是中沒有這個方法啊。所以就想著實現了一個,因為其他的方法也都封裝,不差這一個了。 Fetch 提供了對?Request?和?Response?(以及其他與網絡請求有關的)對象通用的定義。它之后能夠被使用到很多場景中:service wor...
摘要:什么叫是填充式或參數式的簡寫,是通過請求跨域接口,獲取數據的新實現方式的實現原理動態創建標簽,因為標簽是沒有同源策略限制,可以跨域的。具體看接下來的實現這個是庫的具體實現,建議下載來研究一下,最好自己動手寫一遍。 什么叫jsonp? jsonp是json with padding(填充式json或參數式json)的簡寫,是通過ajax請求跨域接口,獲取數據的新實現方式 jsonp的實現...
摘要:不管你好不好,反正我是番茄醬。例如我們要請求的地址是獲取用戶信息后臺應該返回給我們的數據是番茄醬也就是說我們最終需要的是服務器把格式的數據給我們。于是后臺返回給我們番茄醬于是代碼就相當于是番茄醬最終結果與相同。 不管你好不好,反正我是番茄醬。為啥要寫這篇文章呢,因為我想寫。 showImg(https://segmentfault.com/img/remote/146000001846...
摘要:概述項目是基于,成品是一個移動端的音樂播放器,來源于的實戰課程。播放器是全局組件,放在下面,通過傳遞數據,觸發提交,從而使播放器開始工作。將請求的數據格式化后再通過傳遞,組件間共享,實現歌曲的播放切換等。 概述 項目是基于Vue.js,成品是一個移動端的音樂播放器,來源于imooc的實戰課程。自己動手實踐并加以修改拓展。項目的大致流程是Vue-cli構建開發環境,分析需求,設計構思,規...
閱讀 1357·2021-09-02 10:19
閱讀 1101·2019-08-26 13:25
閱讀 2108·2019-08-26 11:37
閱讀 2413·2019-08-26 10:18
閱讀 2676·2019-08-23 16:43
閱讀 2989·2019-08-23 16:25
閱讀 775·2019-08-23 15:53
閱讀 3297·2019-08-23 15:11