⤴Top⤴

XHR & Fetch API

博客分类: 前端

XHR & Fetch API

XHR & Fetch API

什么是 AJAX

AJAX(Asynchronous JavaScript and XML) 是一种技术方案,能够向服务器请求额外的数据而无须卸载页面。其技术核心为 XMLHttpRequest(XHR) 对象,通过它可以发出 HTTP 请求和接收 HTTP 响应。

XHR

XHR level 2

XMLHttpRequest(XHR) 最初只是微软引入的一个特性,后来其他浏览器提供商也提供了相同的实现。之后 W3C 对它进行了标准化,提出了 XMLHttpRequest 标准,其中又分为 Level 1 和 Level 2。

XMLHttpRequest Level 1 主要存在以下缺点:

XMLHttpRequest Level 2 新增了以下功能:

function sendAjax() {
  //构造表单数据
  var formData = new FormData();
  formData.append('username', 'johndoe');
  formData.append('id', 123456);
  //创建 XHR 对象
  var xhr = new XMLHttpRequest();
  // 设置 XHR 请求的超时时间,同步请求只能为 0
  xhr.timeout = 5000;
  // 设置响应返回的数据格式,同步请求无效
  xhr.responseType = ‘text’;
  // 进度事件,可能有浏览器兼容问题
  xhr.onload = function(e) {
    if((this.status >= 200 && this.status < 300) || this.status == 304){
        alert(this.responseText);
    }
  };

  xhr.ontimeout = function(e) { ... }; // 请求超时时调用
  xhr.onerror = function(e) { ... };
  xhr.upload.onprogress = function(e) { ... };

  // 创建一个异步 post 请求
  xhr.open('POST', '/server', true);
  //发送数据
  xhr.send(formData);
}

XHR 方法

// 第一个参数为请求类型,不区分大小写
// 第二个参数为请求的 URL
// 第三个参数为布尔值,表示是否异步发送请求,默认为 true 异步
xhr.open('get', 'https://jsonplaceholder.typicode.com/posts/1', true);
// 接收一个参数,即作为请求主题发送的数据
xhr.send(null);
// 必须在 open 方法之后,send 方法之前调用,否则会抛错
// 多次调用采用追加,最终请求头中显示 'my-header: tate, snow'
xhr.setRequestHeader('my-header', 'tate');
xhr.setRequestHeader('my-header', 'snow');
xhr.getResponseHeader('my-header'); // Refused to get unsafe header "my-header"
xhr.getAllResponseHeaders();
// pragma: no-cache
// content-type: application/json; charset=utf-8
// cache-control: public, max-age=14400
// expires: Wed, 28 Mar 2018 07:31:37 GMT

获取 response 数据

在收到响应后,响应的数据会自动填充 XHR 对象的属性:

onreadystatechange

若采用异步请求的话,XHR 对象的 readyState 属性可以检测当前请求的状态:

// 这里使用 this 对象的话,在部分浏览器可能会导致函数执行失败,因此尽量采用 XHR 实例变量
xhr.onreadystatechange = function() {
  if (xhr.readyState === 4) {
    if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
      alert(xhr.responseText);
    }
  }
}

load 进度事件

Progress Events 进度事件定义了客户端和服务器通信有关的事件:

progress 进度事件可以用来实时显示进度,默认每 50ms 触发一次。需要注意的是,上传过程和下载过程触发的是不同对象的 onprogress 事件:

onprogress 事件处理程序会接收到一个 event 对象,其 target 属性是 XHR 对象,但包含着三个额外的属性:

xhr.onprogress = updateProgress;
xhr.upload.onprogress = updateProgress;
function updateProgress(event) {
  if (event.lengthComputable) {
    statusElement.innerHTML = 'Received ' + event.loaded + ' of ' + event.total + ' bytes';
  }
}

Fetch API

XMLHttpRequest 是一个设计粗糙的 API,不符合关注分离(Separation of Concerns)的原则,配置和调用方式非常混乱,而且基于事件的异步模型写起来也没有现代的 Promise,generator/yield,async/await 友好。因此 Fetch API 的出现就是为了解决 XHR 的问题。

fecth()

Fetch API 提供了一个获取资源的接口(包括跨域),最常用的就是 fetch() 函数。它接收一个 URL 参数,返回一个 promise 来处理 response。

// GET
fetch('https://jsonplaceholder.typicode.com/posts')
  .then(response => response.json())
  .then(json => console.log(json))
// POST
var headers = {
  method: 'POST',
  headers: {
    "Content-type": "application/json; charset=UTF-8"
  },
  body: JSON.stringify({
    title: 'foo',
    body: 'bar',
    userId: 1
  })
}
fetch('https://jsonplaceholder.typicode.com/posts', headers)
  .then(response => response.json())
  .then(json => console.log(json))

Fetch 引入了三个接口,它们分别是 Headers、Request 以及 Response。

Headers

Headers 接口是一个简单的多映射的名-值表。

// 创建一个空的 Headers 对象
var headers = new Headers();

// 添加(append)请求头信息
headers.append('Content-Type', 'text/plain');
headers.append('X-My-Custom-Header', 'CustomValue');

// 判断(has), 获取(get), 以及修改(set)请求头的值
headers.has('Content-Type'); // true
headers.get('Content-Type'); // 'text/plain'
headers.set('Content-Type', 'application/json');

// 删除某条请求头信息
headers.delete('X-My-Custom-Header');

// 创建对象时设置初始化信息
var headers = new Headers({
  'Content-Type': 'application/json',
  'Authorization': 'Bearer ' + token,
});

Request

Request 对象表示一次 fetch 调用的请求信息:

var request = new Request('/users.json', {
  method: 'POST',
  mode: 'cors',
  redirect: 'follow',
  headers: new Headers({
    'Content-Type': 'text/plain'
  })
});

fetch(request).then(function() { /* handle response */ });

Response

Response 代表响应, fetch 的 then 方法接收一个 Response 实例,其可配置的参数如下:

Response 提供的方法如下:

Fetch API 的兼容情况可查看 caniuse,可以使用 whatwg-fetch 填充库进行兼容处理。

参考链接

  1. 你真的会使用 XMLHttpRequest 吗? By ruoyiqing
  2. This API is so Fetching!
  3. fetch API By David Walsh
  4. fetch 没有你想象的那么美 By undefined