JavaScript異步編程之XHR與fetch

個人github github.com/zhuanyongxi…javascript

AJAX模型

圖片左側的部分是有AJAX以前的瀏覽器與服務器交互的方式,是同步的,發出請求以後須要等待,這樣的體驗就很是很差。AJAX的出現改變了這一狀況,由不一樣變成了異步,發出請求以後再也不須要等待。java

XHR

這是最通用的AJAX的API,完整的寫法是XMLHttpRequest。雖然名字裏面有XML,可它所支持的數據類型不僅是XML。ios

經常使用的幾步:git

var xhr = new XMLHttpRequest();
console.log('UNSENT', xhr.readyState);	// readyState will be 0

xhr.open('GET', '/api', true);
console.log('OPENED', xhr.readyState);	// readyState will be 1

xhr.onprogress = function() {
  console.log('LOADING', xhr.readyState);	// readyState will be 3
};
xhr.onreadystatechange = function() {
  if(xhr.readyState === XMLHttpRequest.DONE && xhr.status === 200) {
    console.log(xhr.responseText);
  }
};
xhr.onload = function() {
  console.log('DONE', xhr.readyState);	// readyState will be 4
}
複製代碼

你確定在想我這是從哪抄的代碼吧?從MDN上抄的,連接是這個。其中open這個api的第三個參數默認值是true,也就是異步,false就是同步。一般都是使用異步。另外還要知道一些經常使用的http的狀態碼如:200、30一、30二、30四、400、40一、40四、500、501。github

fetch

與XHR相比,fetch基於promise,寫法更加簡潔優雅,它能夠更好的支持更多的場景,如service workers、Cache API等。web

相信不少人也都用過axios,與axios相比,fetch這個api,總結一下就是:好用的功能都須要本身寫。好比攔截器,自動轉換數據格式等。不過這自己也沒什麼比較的必要,由於他們的定位不一樣,fetch是js的api,編程語言的api,確定會作的很基礎,目光放的更長遠;而axios是一個第三方的方法庫,它存在的意義就是在現有api的基礎上作一次封裝,增長一些好用的方法,不過axios封裝的是XHR,並非fetch。編程

再抄一波代碼,對比fetch與XHR:json

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

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

xhr.onerror = function() {
  console.log("Booo");
};

xhr.send();
複製代碼

一樣的需求用fetch寫:axios

fetch(url).then(function(response) {
  return response.json();
}).then(function(data) {
  console.log(data);
}).catch(function() {
  console.log("Booo");
});
複製代碼

在加上ES6的箭頭函數:api

fetch(url).then(r => r.json())
  .then(data => console.log(data))
  .catch(e => console.log("Booo"))
複製代碼

簡單多了吧?

不過這裏有一個須要注意的地方,fetch只有遇到網絡錯誤或服務端cors未配置的時候纔會reject,就是說像500、404這樣的錯誤,fetch是不會reject的。解決方法就是用response.ok

fetch("http://httpstat.us/500")
  .then(function(response) {
    if (!response.ok) {
      throw Error(response.statusText);
    }
    return response;
  }).then(function(response) {
    console.log("ok");
  }).catch(function(error) {
    console.log(error);
  });
複製代碼

一個能夠參考的對fetch的簡單的封裝:

const options = {
  headers: new Headers({'Content-Type': 'application/json'}),
  cache: 'default',
  method: 'GET',
  mode: 'cors'
}

function get(url, params) {
  const opts = Object.assign({}, options, {method: 'GET'});
  return fetch(`${url}?${querystring.stringify(params)}`, opts)
    .then(data => data.json());
}

function post(url, params) {
  const opts = Object.assign({}, options, {method: 'POST', body: JSON.stringify(params)});
  return fetch(url, opts)
    .then(data => data.json());
}
複製代碼

這一段也是抄的,但我不告訴你我是在哪抄的。

使用fetch須要注意的幾個地方

  • 默認不帶cookie,本身加;

    fetch(url, {
      credentials: 'include'
    })
    複製代碼
  • 不支持同步;

  • 不支持取消;

  • 沒法查看請求進度。

參考資料:

相關文章
相關標籤/搜索