JavaScript JSON 與 AJAX|8月更文挑戰

JSON 的概念

  1. 全部編程語言都離不開的三大數據結構javascript

    scalar 標量:數字和字符串html

    sequence 序列:數組和列表java

    mapping 映射:鍵值對ajax

  2. JSON:JavaScript Object Notation,輕量級的數據交互格式正則表達式

  3. JSON 數據是沒有方法的普通對象,或者是包含這種對象的數組編程

    var person = {
        "name": "jett",
        "age": "22",
        "sex": "男"
    }
    var persons = [
        {
        "name": "jett",
        "age": "22",
        "sex": "男"
    	},
        {
        "name": "lily",
        "age": "20",
        "sex": "女"
    	}
    ]
    複製代碼

JSON 的基本格式

  1. 鍵值對以冒號隔開
  2. 鍵名強制使用雙引號
  3. 並列數據用逗號隔開
  4. 並列數據集合用[]包圍

JSON 與對象的轉換

  1. JSON 轉換成 JS 對象json

    JSON.parse()跨域

    <div id='box' data-info='{"name":"Jett","age":"22"}'></div>
    複製代碼
    // JSON.parse(str) str -> object
    var box = document.getElementById('box');
    var jsonData = 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()
    複製代碼
  2. JS 對象轉換 JSON瀏覽器

    JSON.stringify()

    var obj = {
            name: 'Jett',
            age: 22,
            sex: '男'
        }
    var jsonData  = JSON.stringify(obj);
    console.log(jsonData);
    // {"name":"Jett","age":22,"sex":"男"}
    複製代碼

AJAX 的概念

  1. AJAX:Asynchronous JavaScript and XML,異步的 JavaScript 和 XML

  2. AJAX 不是新的編程語言,而是一種使用現有標準的新方法

  3. AJAX 最大的優勢是在不從新加載整個頁面的狀況下,能夠與服務器交換數據並更新部分網頁內容

  4. AJAX 工做原理

    瀏覽器建立 XMLHttpRequest 對象,發送 AJAX 請求

    服務器接收請求,建立響應,返回數據

    瀏覽器接收數據,動態渲染頁面

AJAX 的基本寫法

  1. 建立 XMLHttpRequest 對象

    XMLHttpRequest 用於在後臺與服務器交換數據

    兼容 IE7 及以上

    var xmlhttp;
    if (window.XMLHttpRequest) {
        xmlhttp = new XMLHttpRequest();
    } else {
        // 兼容 IE6/5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    複製代碼
  2. 發送 AJAX 請求

    GET 請求

    url 爲請求地址,在地址後使用 ? 拼接消息內容,如 ?name=Jett&age=22

    xmlhttp.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 表明同步

  3. 監聽響應狀態

    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) {
            // ...
        }
    }
    複製代碼
  4. 處理響應

    XMLHttpRequest 對象的 responseText 或 responseXML 屬性用於接收服務端返回的數據

    顧名思義,respnseXML 用於接收 XML 格式的響應數據,responseText 用於接收通常數據

    xmlhttp.onreadystatechange=function() {
        if (xmlhttp.readyState==4 && xmlhttp.status==200) {
            console.log(xmlhttp.responseText);
            // 得到響應數據並使用
        }
    }
    複製代碼

JSONP 的概念

  1. 跨域請求

    URL = 協議名 + 主機名 + 端口號 + 資源名稱

    域 = 協議名 + 主機名 + 端口號

    出於安全性考慮,只有當頁面所在域和請求的目的地址在同一域才容許訪問

  2. JSONP 是一種跨域解決方案

    目前解決瀏覽器跨域問題的方法有 JSONP、cors 策略等,cors 策略是 HTML5 的新特性,老版本瀏覽器可能不支持,JSONP 是最經常使用的處理方式

JSONP 的原理

  1. 在 HTML 衆多標籤中,有些標籤具備跨域功能,如 script、img、iframe

  2. 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 代碼來執行,就是執行頁面中定義的方法,恰好能夠將其中的參數順利帶到頁面中

  3. 咱們在頁面上定義一個函數,將其函數名經過 URL 查詢字符串傳到服務端,服務端拼接字符串,返回執行該函數的 JS 代碼,並將要傳遞的數據放在參數中,這樣在頁面上定義好的函數就能夠被執行,而且獲得了服務端傳來的數據,在該函數內執行成功回調,就能夠對服務端數據進行處理了

JSONP 回調函數

  1. 對於普通 AJAX 請求咱們能夠經過監聽 XMLHttpRequest 的 readystatechange 事件,判斷 readystate 和 status 來知曉請求和響應是否完成,以執行成功回調或出錯回調

  2. JSONP 方式本質上是利用 script 標籤的 src 進行請求,響應狀況以下:

  • 若是 src 指向資源存在,且其返回的字符串被當成 JS 代碼成功執行

    即頁面內定義好的函數被成功執行,該函數內的成功回調函數能夠經過參數拿到數據進行處理

  • 若是 src 指向的目的資源訪問不到

    script 標籤會觸發 error 事件,監聽此事件能夠得到執行出錯回調的時機

    var script = document.createElement('script');
    script.onerror = funtion() {
        // 執行出錯回調函數
    }
    複製代碼
  • 若是 src 指向資源存在,返回的字符串會由於是 script 標籤而被執行,執行過程當中出錯

    在執行成功回調函數前,對 script 標籤對象添加一個標記屬性,監聽 script 的 load 事件發生時對象是否有該標籤屬性

    由於 onload 函數在 script 標籤加載完成後執行,script 標籤在其引入的代碼執行後,纔會響應 onload 處理函數,經過判斷標記屬性是否添加成功,能夠知曉 script 標籤引入的代碼是否成功執行,若是標記屬性爲 undefined,則執行出錯回調

    若是觸發 error 事件,onerror 事件處理函數將執行,但 onload 將不執行,由於目標資源訪問出錯,並無加載完成

    var script = document.createElement('script');
    window.callback = function (res) {
        script['jsonp'] = 1;
        // 執行成功回調函數
    }
    script.onload = function () {
        if (typeof script['jsonp'] === 'undefined') {
            // 執行出錯回調函數
        }
    }
    複製代碼
  1. 須要注意的是,IE8 及如下 script 標籤對象不支持 onerror,也不支持 onload,但支持 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') {
                // 執行出錯回調函數
            }
        }
    }}
    複製代碼
  2. 函數名動態生成,利用 onload 配合 onreadystate 判斷加載狀態,執行完畢後 delete 對應函數,並 remove 對應 script 標籤節點

    在本身封裝 JSONP 函數時,咱們可能會在 window 對象下動態添加函數如 callback,這樣 script 的 src 指定資源返回形如 callback('數據') 的字符串數據,就能夠直接執行此函數並獲取數據,可是咱們在優化 JSONP 函數時,會但願將動態建立的函數刪除,在 IE8 中 delete window 下的屬性會報不支持,咱們能夠在 Window.prototype 上添加函數,一樣能夠在直接執行,且支持 delete

AJAX 與 JSONP 的封裝

  1. 封裝一個 ajax 函數,支持 get、post、jsonp 三種形式的請求,以對象形式傳入參數

  2. 配置項

    var opt = {
        type: 'get', 
    	url: 'http://...',
    	data: { // 數據使用對象形式
          name: 'zzh',
          age: '21'
        },
    	async: true, // 默認 true
    	success: function(res) {
            
        },
    	error: function() {
            
        },
    	timeout: 3000 // 默認 60000
    }
    複製代碼
  3. 代碼

    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 = 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 = 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 = 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 及以上支持 onerror
                // onerror 用於請求失敗,未執行 callback
                // onload 用於請求成功,但執行 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() 執行了');
        }
    })
    複製代碼
相關文章
相關標籤/搜索