Ajax 之战:XMLHttpRequest 与 Fetch API( 三 )


const xhr = new XMLHttpRequest();// progress eventxhr.upload.onprogress = (p) => {console.log(Math.round((p.loaded / p.total) * 100) + "%");};事件处理程序传递的对象有三个属性:

  1. lengthComputable —— 如果进度可以计算,则设置为 true
  2. total —— 消息体的工作总量或内容长度
  3. loaded —— 到目前为止完成的工作或内容的数量
Fetch API 没有提供任何方法来监控上传进度 。
超时支持
XMLHttpRequest 对象提供了一个 timeout 属性,可以将其设置为请求自动终止前允许运行的毫秒数;如果超时,就触发一个 timeout 事件来处理:
const xhr = new XMLHttpRequest();xhr.timeout = 5000; // 5-second maximumxhr.ontimeout = () => console.log("timeout");fetch() 中可以封装一个函数来实现超时功能:
function fetchTimeout(url, init, timeout = 5000) {return new Promise((resolve, reject) => {fetch(url, init).then(resolve).catch(reject);setTimeout(reject, timeout);});}或者,你可以使用 Promise.race():
Promise.race([fetch("/service", { method: "GET" }),new Promise((resolve) => setTimeout(resolve, 5000)),]).then((res) => console.log(res));这两个方法都不容易使用,另外请求将在后台继续运行 。
中止支持
运行中的请求可以通过 XMLHttpRequest 的 abort() 方法取消,如有必要,可以附加一个 abort 事件来处理:
const xhr = new XMLHttpRequest();xhr.open("GET", "/service");xhr.send();// ...xhr.onabort = () => console.log("aborted");xhr.abort();你可以中止一个 fetch(),但它不是那么直接,需要一个 AbortController 对象:
const controller = new AbortController();fetch("/service", {method: "GET",signal: controller.signal,}).then((res) => res.json()).then((json) => console.log(json)).catch((error) => console.error("Error:", error));// abort requestcontroller.abort();当 fetch() 中止时,catch() 块执行 。
更显式的故障检测
当开发人员第一次使用 fetch() 时,假设一个 HTTP 错误,如 404 Not Found 或 500 Internal Server error 将触发 Promise 拒绝并运行相关的 catch() 块,这似乎是合乎逻辑的,但事实并非如此:Promise 成功地解决了这些响应,只有当网络没有响应或请求被中断时,才会发生拒绝 。
fetch() 的 Response 对象提供了 status 和 ok 属性,但并不总是显式地需要检查它们,XMLHttpRequest 更明确,因为单个回调函数处理每一个结果:你应该在每个示例中都看到 stuatus 检查 。
浏览器支持
我希望你不必支持 Internet Explorer 或 2015 年之前的浏览器版本,但如果是这样的话,XMLHttpRequest 是你唯一的选择 。XMLHttpRequest 也很稳定的,API 不太可能更新 。Fetch 比较新,还缺少几个关键特性,虽然更新不太可能破坏代码,但你可以期待一些维护 。
应该使用哪个 API ?
大多数开发人员都会使用更新的 Fetch API,它的语法更简洁,比 XMLHttpRequest 更有优势;也就是说,这些好处中的许多都有特定的用例,但在大多数应用程序中都不需要它们 。只有两种情况下 XMLHttpRequest 仍必不可少:
  1. 你正在支持非常老的浏览器——这种需求会随着时间的推移而下降 。
  2. 你需要显示上传进度条 。Fetch 后续将会支持,但可能需要几年的时间 。
这两种选择都很有趣,值得详细了解它们!




推荐阅读