【重读红宝书系列】第24章-网络请求与远程资源

142 阅读4分钟

1、XMLHttpRequest对象

是什么

把 Ajax 推到历史舞台上的关键技术是 XMLHttpRequest(XHR)对象。这个对象最早由微软发明, 然后被其他浏览器所借鉴。xhr 对象支持发送同步请求、异步请求

怎么用

xhr使用较为复杂,axios对其进行了封装

// 1、创建xhr对象
let xhr = new XMLHttpRequest();

// 2、设置请求参数
// open的第三个参数用于控制是否异步,默认true,异步
xhr.open("get", "https://www.yuque.com/", true);

// 3、监听状态变化
xhr.onreadystatechange = function () {
  if (xhr.readyState === 4 && xhr.status === 200) {
    console.log(xhr.responseText);
  }
};

// 4、设置请求头
xhr.setRequestHeader("MyHeader", "MyValue");

// 5、请求发出去
xhr.send();

readyState是什么?

xhr.readyState 表示当前处在请求/响应过程的哪个阶段,这个属性有如下可能的值

0:未初始化(Uninitialized)。尚未调用 open()方法

1:已打开(Open)。已调用 open()方法,尚未调用 send()方法

2:已发送(Sent)。已调用 send()方法,尚未收到响应

3:接收中(Receiving)。已经收到部分响应

4:完成(Complete)。已经收到所有响应,可以使用了

如何中断请求?

xhr.abort(),调用这个方法后,XHR 对象会停止触发事件,并阻止访问这个对象上任何与响应相关的属性

进度事件

Progress Events 下有6 个进度相关的事件:

 loadstart:在接收到响应的第一个字节时触发

 progress:在接收响应期间反复触发

 error:在请求出错时触发

 abort:在调用 abort() 终止连接时触发

 load:在成功接收完响应时触发

 loadend:在通信完成时,且在 error、abort 或 load 之后触发

每次请求都会首先触发 loadstart 事件,之后是一个或多个 progress 事件,接着是 error、abort 或 load 中的一个,最后以 loadend 事件结束


重点介绍下 load、progress 事件

load 事件: 只要是从服务器收到响应,无论状态码是什么,都会触发 load 事件

let xhr = new XMLHttpRequest();

xhr.onload = function () {
  if ((xhr.status >= 200 && xhr.status < 300) || xhr.status == 304) {
    alert(xhr.responseText);
  } else {
    alert("Request was unsuccessful: " + xhr.status);
  }
};

xhr.open("get", "altevents.php", true);

xhr.send(null);

progress 事件: 在浏览器接收数据期间,这个事件会被持续触发,其回调的 event 对象中有两个关键属性---loaded、total,前者表示浏览器当前接收到的数据大小,后者表示本次请求的总数据大小

实际应用:文件下载,如果后端无法提供进度字段,前端可以用以上属性模拟下载进度

xhr.onprogress = function (event) {
  let loaded = event.loaded;
  let total = event.total;
  if (event.lengthComputable) {
    console.log("下载进度:" + (loaded / total) * 100 + "%");
  }
};

2、fetch函数

是什么

fetch 函数能够执行 XMLHttpRequest 对象的所有任务,但更容易使用,接口也更现代化。与xhr的一大不同是,xhr 可以选择同步还是异步请求,而 fetch 函数 只能发异步请求

怎么用

浏览器环境下,直接调用 fetch 函数,传入URL、配置对象等,返回值是一个 Promise

fetch('"https://www.yuque.com/"', {
  // 配置对象,可以配置请求头、请求方式、请求体等等
  method: "get",
})
  .then(async (res) => {
    let data = await res.text();
  })
  .catch((err) => {
    console.log(err);
  });

如何中断请求?

用 AbortController 对象对中断请求。调用 AbortController. abort() 会中断所有网络传输,特别适合希望停止传输大型负载的情况

// 中断请求
let abortController = new AbortController();

fetch("wikipedia.zip", { signal: abortController.signal })
 .catch(() =>console.log("aborted!"));

// 10 毫秒后中断请求
setTimeout(() => abortController.abort(), 10);

3、sendBeacon 函数

navigator 对象增加了一个 sendBeacon() 方法,主要用于在页面卸载(如关闭页面、跳转页面)时,异步地向服务器发送少量数据

它和 xhr 相比的优势:如果 xhr 请求是同步的,会阻塞页面卸载,导致用户体验变差;如果 xhr 是异步的,在页面卸载时请求可能还未发出去就被终止,从而无法保证数据能成功发送到服务器

这个简单的方法接收一个 URL 和一个数据有效载荷参数,并会发送一个 POST 请求

navigator.sendBeacon(
  "https://example.com/analytics-reporting-url",
  '{foo: "bar"}'
);

特性:

 sendBeacon() 并不是只能在页面生命周期末尾使用,而是任何时候都可以使用

 调用 sendBeacon() 后,浏览器会把请求添加到一个内部的请求队列,因此它异步、不阻塞主线程

 浏览器保证在原始页面已经关闭的情况下也会发送请求

 状态码、超时和其他网络原因造成的失败完全是不透明的,不能通过编程方式处理