fetch與ajax(XMLHttpRequest)相比

前言

ES6中新增了一種HTTP數據請求的方式,就是fetch,它和XMLHttpRequest有許多類似的功能,可是相比XMLHttpRequest,fetch被設計成更具可擴展性和高效性。江湖上一直流傳着 「傳統ajax已死,fetch永生」的說法,下面詳細說下兩者

詳情

1.XMLHttpRequest 請求數據

var xhr = new XMLHttpRequest();
xhr.open('GET', url);
xhr.responseType = 'json';

xhr.onload = function() {
  console.log(xhr.response);
};

xhr.onerror = function() {
  console.log("Oops, error");
};

xhr.send();

2. fetch請求數據

fetch(url)
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(e => console.log("Oops, error", e))

兩段代碼相比之下,fetch更爲簡潔,並且fetch請求屬於promise結構,直接.then()方法處理回調數據,當出錯時,會執行catch方法,並且promise避免了回調金字塔的問題。javascript

3.fetch瀏覽器支持狀況

目前谷歌瀏覽器對fetch的支持良好,具體支持狀況以下圖html

clipboard.png

固然,你也能夠去這裏查看can i usejava

4.fetch請求的四種方式

get請求

fetch(url)
    .then(response => response.json())
    .then(data => console.log(data))
    .catch(e => console.log("Oops, error", e))

若是須要傳遞參數,須要拼接在url
後面這裏的調用的第一個then函數裏面,返回結果是一個可讀流形式git

clipboard.png

若是請求的是json數據,須要調用response.json()(這裏的response是傳遞的參數)將可讀流解析爲json數據,在下一個then方法中,就能夠獲得想要的json數據了es6

clipboard.png

同理,若是請求的txt文本數據,則須要調用response.text()來解析...更多調用的解析方法以下github

response.arrayBuffer()
讀取 Response對象而且將它設置爲已讀(由於Responses對象被設置爲了 stream 的方式,因此它們只能被讀取一次) ,並返回一個被解析爲ArrayBuffer格式的promise對象

response.blob()
讀取 Response對象而且將它設置爲已讀(由於Responses對象被設置爲了 stream 的方式,因此它們只能被讀取一次) ,並返回一個被解析爲Blob格式的promise對象

response.formData()
讀取Response對象而且將它設置爲已讀(由於Responses對象被設置爲了 stream 的方式,因此它們只能被讀取一次) ,並返回一個被解析爲FormData格式的promise對象

response.json()
讀取 Response對象而且將它設置爲已讀(由於Responses對象被設置爲了 stream 的方式,因此它們只能被讀取一次) ,並返回一個被解析爲JSON格式的promise對象

response.text()
讀取 Response對象而且將它設置爲已讀(由於Responses對象被設置爲了 stream 的方式,因此它們只能被讀取一次) ,並返回一個被解析爲USVString格式的promise對象

對於catch方法,只有報程序出錯的時候纔會執行。ajax

post請求

fetch(url,{
            method:'POST',
            headers:{
                'Content-type':'application/json'// 設置請求頭數據類型
            },
            body:data
        })
        .then(res=>res.json())
        .then(data=>console.log(data))

method:設置設置請求的方式,默認是get,另外還有PUTDELETE
headers:設置請求頭信息,固然,這裏面還能夠設置別的信息,好比:json

var u = new URLSearchParams();
u.append('method', 'flickr.interestingness.getList');
u.append('api_key', '<insert api key here>');
u.append('format', 'json');
u.append('nojsoncallback', '1');

fetch(url,{
            method:'POST',
            headers:u,
            body:data
        })
        .then(res=>res.json())
        .then(data=>console.log(data))

另外,fetch能夠在header中設置CORS跨域後端

u.append("Access-Control-Allow-Origin", "*");  
    u.append("Access-Control-Allow-Headers", "X-Requested-With");  
    u.append("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS");  
    u.append("X-Powered-By",' 3.2.1')

若是服務器不支持CORSfetch提供了三種模式,其中no-cors能夠繼續訪問服務器

fetchmode配置項有3個值,以下:api

  • same-origin:該模式是不容許跨域的,它須要遵照同源策略,不然瀏覽器會返回一個error告知不能跨域;其對應的response type爲basic。
  • cors: 該模式支持跨域請求,顧名思義它是以CORS的形式跨域;固然該模式也能夠同域請求不須要後端額外的CORS支持;其對應的response typecors
  • no-cors: 該模式用於跨域請求可是服務器不帶CORS響應頭,也就是服務端不支持CORS;這也是fetch的特殊跨域請求方式;其對應的response typeopaque

針對跨域請求,cors模式是常見跨域請求實現,可是fetch自帶的no-cors跨域請求模式則較爲陌生,該模式有一個比較明顯的特色:

該模式容許瀏覽器發送本次跨域請求,可是不能訪問響應返回的內容,這也是其response type爲opaque透明的緣由,以下圖:

clipboard.png

呃,感受這樣雖然解決能跨域問題,可是請求不到任何數據,仍是沒有卵用...

注意: cors 支持 三種content-type 不支持 application/json

  • application/x-www-form-urlencoded
  • multipart/form-data
  • text/plain

body:須要傳遞的參數

fetch請求默認是不會攜帶cookie信息,若是想要攜帶,須要在手動設置

fetch(url, {
              method: 'POST',
              headers:{
                'Content-type':'application/json'// 設置請求頭數據類型
                },
              credentials: "include" 
            })

credentials: "include" 設置請求頭攜帶cookie信息

put請求

fetch(url,{
            method:'PUT',
            headers:{
                'Content-type':'application/json'// 設置請求頭數據類型
            },
            body:data
        })
        .then(res=>res.json())
        .then(data=>console.log(data))

delete請求

fetch(url,{
            method:'DELETE',
            headers:{
                'Content-type':'application/json'// 設置請求頭數據類型
            },
            body:data
        })
        .then(res=>res.json())
        .then(data=>console.log(data))

其實,post,put,delete,這三個請求代碼上差很少,只是method中對應不一樣的請求方法不一樣而已。

以下是本身封裝的fetch的API代碼

HTML頁面

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>

  <script src="easyhttp.js"></script>
  <script src="app.js"></script>
</body>
</html>

app.js

const url = 'http://jsonplaceholder.typicode.com/users';

let easyHttp = new EasyHttp;

// 請求數據
easyHttp.get(url)
        .then(res=>console.log(res))
        .catch(err=>console.log(err))


// 發送數據
const data = {
    name:"Henry",
    username:"露絲",
    email:"lusi@qq.com"
  };
// easyHttp.post(url,data)
//         .then(res=>console.log(res))
//         .catch(err=>console.log(err))


// 修改數據
// easyHttp.put(url+'/10',data)
//         .then(res=>console.log(res))
//         .catch(err=>console.log(err))

easyHttp.delete(url+'/2',data)
        .then(res=>console.log(res))
        .catch(err=>console.log(err))

easyhttp.js

/**
 * fetch 增刪改查 的API封裝
 */

 class EasyHttp{
    //  get 請求
    get(url){
        return new Promise((resolve,reject)=>{
            fetch(url)
                .then(res=>res.json())
                .then(data=>resolve(data))
                .catch(err=>reject(err))
        })
    }

    // post 請求

    post(url,data){
        return new Promise((resolve,reject)=>{
            fetch(url,{
                method:'POST',
                headers:{
                    'Content-type':'application/json'// 設置請求頭數據類型
                },
                body:data
            })
            .then(res=>res.json())
            .then(data=>resolve(data))
            .then(err=>reject(err))
        })
    }


    // put 請求修改數據
    put(url,data){
        return new Promise((resolve,reject)=>{
            fetch(url,{
                method:'PUT',
                headers:{
                    'Content-type':'application/json'// 設置請求頭數據類型
                },
                body:data
            })
            .then(res=>res.json())
            .then(data=>resolve(data))
            .then(err=>reject(err))
        })
    }

      // delete 刪除數據
      delete(url,data){
        return new Promise((resolve,reject)=>{
            fetch(url,{
                method:'DELETE',
                headers:{
                    'Content-type':'application/json'// 設置請求頭數據類型
                },
                body:data
            })
            .then(res=>res.json())
            .then(data=>'刪除數據成功。。。')
            .then(err=>reject(err))
        })
    }

 }

源碼地址戳一下

最後總結

fetchXMLHttpRequest相比,主要有如下優勢:

  • 語法簡潔,更加語義化
  • 基於標準 Promise 實現,支持 async/await
  • 同構方便,使用 isomorphic-fetch

參考文章

MDN Fetch API

ECMAScript 6 入門

Fetch相比Ajax有什麼優點?

【fetch跨域請求】cors

相關文章
相關標籤/搜索