JavaScript JSON 與 AJAX
JSON 是一種輕量的資料互動格式,與 AJAX 配合完成前端與服務端的資訊傳遞,本文介紹 JSON 的使用、原生 AJAX 寫法、JSONP 跨域解決方法以及 AJAX 和 JSONP 工具函式的封裝
JSON 的概念
-
所有編程語言都離不開的三大資料結構
scalar 標量:數字和字串
sequence 序列:陣列和串列
mapping 映射:鍵值對
-
JSON:JavaScript Object Notation,輕量級的資料互動格式
-
JSON 資料是沒有方法的普通物件,或者是包含這種物件的陣列
var person = { "name": "jett", "age": "22", "sex": "男" } var persons = [ { "name": "jett", "age": "22", "sex": "男" }, { "name": "lily", "age": "20", "sex": "女" } ]
JSON 的基本格式
- 鍵值對以冒號隔開
- 鍵名強制使用雙引號
- 并列資料用逗號隔開
- 并列資料集合用
[]包圍
JSON 與物件的轉換
-
JSON 轉換成 JS 物件
JSON.parse()
<div id='box' data-info='{"name":"Jett","age":"22"}'></div>// JSON.parse(str) str -> object var box = document.getElementById('box'); var jsonData = https://www.cnblogs.com/cadecode/p/box.getAttribute('data-info'); var obj = JSON.parse(jsonData); console.log(obj); // {name:"Jett",age:"22"}eval()
var obj = eval('('+jsonData+')'); // eval 可以執行任何 JS 代碼,所以可以將 jsonData 當作代碼執行 // 為安全性考慮,最好使用 JSON.parse() -
JS 物件轉換 JSON
JSON.stringify()
var obj = { name: 'Jett', age: 22, sex: '男' } var jsonData = https://www.cnblogs.com/cadecode/p/JSON.stringify(obj); console.log(jsonData); // {"name":"Jett","age":22,"sex":"男"}
AJAX 的概念
-
AJAX:Asynchronous JavaScript and XML,異步的 JavaScript 和 XML
-
AJAX 不是新的編程語言,而是一種使用現有標準的新方法
-
AJAX 最大的優點是在不重新加載整個頁面的情況下,可以與服務器交換資料并更新部分網頁內容
-
AJAX 作業原理
瀏覽器創建 XMLHttpRequest 物件,發送 AJAX 請求
服務器接收請求,創建回應,回傳資料
瀏覽器接收資料,動態渲染頁面
AJAX 的基本寫法
-
創建 XMLHttpRequest 物件
XMLHttpRequest 用于在后臺與服務器交換資料
兼容 IE7 及以上
var xmlhttp; if (window.XMLHttpRequest) { xmlhttp = new XMLHttpRequest(); } else { // 兼容 IE6/5 xmlhttp = new ActiveXObject("Microsoft.XMLHTTP"); } -
發送 AJAX 請求
GET 請求
url 為請求地址,在地址后使用
?拼接訊息內容,如 ?name=Jett&age=22xmlhttp.open('GET',url, true); xmlhttp.send();POST 請求
send 方法內傳入訊息內容,如:name=Jett&age=22
xmlhttp.open('POST',url, true); // xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded"); // 通過 setRequestHeader 設定請求頭 xmlhttp.send(data);GET 請求比 POST 更快,但安全性低,且傳輸資料的大小有限制
第三引數 true 代表異步,fasle 代表同步
-
監聽回應狀態
XMLHttpRequest 物件有 readystatechange 事件,用于監聽 readystate 的改變
XMLHttpRequest 物件的 readystate 表示 AJAX 請求的狀態
0: 請求未初始化 1: 服務器連接已建立 2: 請求已接收 3: 請求處理中 4: 請求已完成,且回應已就緒XMLHttpRequest 物件的 status 表示 http 請求的狀態碼
200: 請求 404: 未找到頁面監聽 readystatachange 事件,并判斷狀態
當 xmlhttp.readyState 為 4,xmlhttp.status 為 200 時,代表請求成功且回應就緒
xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { // ... } } -
處理回應
XMLHttpRequest 物件的 responseText 或 responseXML 屬性用于接收服務端回傳的資料
顧名思義,respnseXML 用于接收 XML 格式的回應資料,responseText 用于接收一般資料
xmlhttp.onreadystatechange=function() { if (xmlhttp.readyState==4 && xmlhttp.status==200) { console.log(xmlhttp.responseText); // 獲得回應資料并使用 } }
JSONP 的概念
-
跨域請求
URL = 協議名 + 主機名 + 埠號 + 資源名稱
域 = 協議名 + 主機名 + 埠號
出于安全性考慮,只有當頁面所在域和請求的目的地址在同一域才允許訪問
-
JSONP 是一種跨域解決方案
目前解決瀏覽器跨域問題的方法有 JSONP、cors 策略等,cors 策略是 HTML5 的新特性,老版本瀏覽器可能不支持,JSONP 是最常用的處理方式
JSONP 的原理
-
在 HTML 眾多標簽中,有些標簽具有跨域功能,如 script、img、iframe
-
JSONP 就是利用 script 標簽的跨域能力,動態生成一個 script 標簽,指定 src 為請求地址
頁面中定義的方法
<scrip type="text/javascript"> funtion test(data) { console.log(data); } </scrip> <!--動態生成的 script 標簽--> <script type="text/javascript" src="htpp://localhost:8888"></script>htpp://localhost:8888 地址回傳的資料
test('這是請求回傳的資料')將生成的 script 標簽添加到 DOM 中,瀏覽器根據 src 請求目的地址,得到回傳的資料,因為是 script 標簽,瀏覽器會將回傳的資料當成 JS 代碼來執行,就是執行頁面中定義的方法,剛好可以將其中的引數順利帶到頁面中
-
我們在頁面上定義一個函式,將其函式名通過 URL 查詢字串傳到服務端,服務端拼接字串,回傳執行該函式的 JS 代碼,并將要傳遞的資料放在引數中,這樣在頁面上定義好的函式就可以被執行,并且得到了服務端傳來的資料,在該函式內執行成功回呼,就可以對服務端資料進行處理了
JSONP 回呼函式
-
對于普通 AJAX 請求我們可以通過監聽 XMLHttpRequest 的 readystatechange 事件,判斷 readystate 和 status 來知曉請求和回應是否完成,以執行成功回呼或出錯回呼
-
JSONP 方式本質上是利用 script 標簽的 src 進行請求,回應情況如下:
-
如果 src 指向資源存在,且其回傳的字串被當成 JS 代碼成功執行
即頁面內定義好的函式被成功執行,該函式內的成功回呼函式可以通過引數拿到資料進行處理
-
如果 src 指向的目的資源訪問不到
script 標簽會觸發 error 事件,監聽此事件可以獲得執行出錯回呼的時機
var script = document.createElement('script'); script.onerror = funtion() { // 執行出錯回呼函式 } -
如果 src 指向資源存在,回傳的字串會因為是 script 標簽而被執行,執行程序中出錯
在執行成功回呼函式前,對 script 標簽物件添加一個標記屬性,監聽 script 的 load 事件發生時物件是否有該標簽屬性
因為 onl oad 函式在 script 標簽加載完成后執行,script 標簽在其引入的代碼執行后,才會回應 onl oad 處理函式,通過判斷標記屬性是否添加成功,可以知曉 script 標簽引入的代碼是否成功執行,如果標記屬性為 undefined,則執行出錯回呼
如果觸發 error 事件,onerror 事件處理函式將執行,但 onl oad 將不執行,因為目標資源訪問出錯,并沒有加載完成
var script = document.createElement('script'); window.callback = function (res) { script['jsonp'] = 1; // 執行成功回呼函式 } script.onload = function () { if (typeof script['jsonp'] === 'undefined') { // 執行出錯回呼函式 } }
-
需要注意的是,IE8 及以下 script 標簽物件不支持 one rror,也不支持 onl oad,但支持 onreadystatechange
通過判斷 readystate 來知曉 script 標簽的加載狀態,當 readystate 為 loaded 或 complete 時,表示 script 標簽加載完成,即 script 標簽引入的代碼已經執行,同樣的,在成功回呼函式前為 script 物件添加標記屬性,通過判斷標記屬性是否添加成功,可以知曉 script 標簽引入的代碼是否成功執行,如果標記屬性為 undefined,則執行出錯回呼
script.onreadystatechange = function () { // 正則運算式判斷 readystate 是否為 loaded 或 complete if (/loaded|complete/i.test(this.readyState)) { if (typeof script['jsonp'] === 'undefined') { // 執行出錯回呼函式 } } }} -
函式名動態生成,利用 onl oad 配合 onreadystate 判斷加載狀態,執行完畢后 delete 對應函式,并 remove 對應 script 標簽節點
在自己封裝 JSONP 函式時,我們可能會在 window 物件下動態添加函式如 callback,這樣 script 的 src 指定資源回傳形如 callback('資料') 的字串資料,就可以直接執行此函式并獲取資料,但是我們在優化 JSONP 函式時,會希望將動態創建的函式洗掉,在 IE8 中 delete window 下的屬性會報不支持,我們可以在 Window.prototype 上添加函式,同樣可以在直接執行,且支持 delete
AJAX 與 JSONP 的封裝
-
封裝一個 ajax 函式,支持 get、post、jsonp 三種形式的請求,以物件形式傳入引數
-
配置項
var opt = { type: 'get', url: 'http://...', data: { // 資料使用物件形式 name: 'zzh', age: '21' }, async: true, // 默認 true success: function(res) { }, error: function() { }, timeout: 3000 // 默認 60000 } -
代碼
function ajax(option) { // 設定默認引數 var opt = { type: option.type.toUpperCase(), url: option.url, data: option.data || null, async: option.async || false, success: option.success, error: option.error, timeout: option.timeout || 60000 }; // 用于 jsonp 的回呼函式名 var callback = 'callback' + new Date().getTime(); var type = opt.type, success = opt.success, error = opt.error, data = https://www.cnblogs.com/cadecode/p/parseData(opt.data); // 將 data 物件裝換成查詢字串 if (type ==='GET' || type === 'POST') { var xhr = new XMLHttpRequest(); xhr.onreadystatechange = function () { if (xhr.readyState === 4 && xhr.status === 200) { success && success(xhr.responseText, xhr.status); } else { error && error(xhr.status); } } if (type == 'GET') { opt.url += data; data = https://www.cnblogs.com/cadecode/p/null; } xhr.open(type, opt.url, opt.async); xhr.send(data); setTimeout(function () { xhr.abort(); console.error(opt.url +'請求超時'); }, opt.timeout); } else if (type === 'JSONP') { var script = document.createElement('script'); script.src = https://www.cnblogs.com/cadecode/p/opt.url + data; // 選則存放在 Window 原型上,window 下可以使用 // 如果直接存放在 window 上,IE8 window 屬性不支持 dalete Window.prototype[callback] = function (res) { script['jsonp'] = 1; success && success(res); } document.body.appendChild(script); // -[1,] 在 IE8 回傳 NaN,IE9 及以上回傳 -1 if (-[1,]) { // IE9 及以上支持 one rror // one rror 用于請求失敗,未執行 callback // onl oad 用于請求成功,但執行 callback 出錯 script.onerror = script.onload = function () { if (typeof script['jsonp'] === 'undefined') { error && error(); } script.parentNode.removeChild(script); delete Window.prototype[callback]; } } else { // script.onreadystatechange 兼容 IE8 script.onreadystatechange = function () { // -[1,] 在 IE8 回傳 NaN,IE9 及以上回傳 -1 if (/loaded|complete/i.test(this.readyState)) { if (typeof script['jsonp'] === 'undefined') { error && error(); } script.parentNode.removeChild(script); delete Window.prototype[callback]; } } } } function parseData(data) { var arr = [], str; if (type === 'GET') { str = '?'; } else if (type === 'POST') { str = ''; } else if (type === 'JSONP') { str = '?callback=' + callback + '&'; } for (var k in data) { arr.push(k + '=' + data[k]); } return str + arr.join('&'); } } // 使用示例 ajax({ type: 'jsonp', url: 'http://127.0.0.1:8888/', data: { name: 'jett', age: 22 }, success: function (res) { console.log('接收資料:' + res); }, error: function () { console.log('error() 執行了'); } })
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/135967.html
標籤:JavaScript
