ajax

image-20220627164153070

ajax 其实并不是一个发请求的方式,它是多种技术的组合,是一个思想,全称为,Asynchronous JavaScript And XML 即异步 JavaScript 和 XML,并不能吧 ajax 和 XMLHttpRequest 划上等号。

ajax 的特点就是局部刷新页面,无需重载整个页面。

XHR 是实现 ajax 的一种手段

<script>
const request=new XMLHttpRequest();
request.open("get","api/getSomething");
request.onreadystatechange=()=>{
if(request.readState===4){
if(request.status===200){
//doSomething for responce
}
}
}
request.send();
</script>

axios

基于 promise 对 XMLHttpRequest 的二次封装

其特点:

  • 从浏览器中创建 XMLHttpRequests(不同环境)
  • 从 node.js 创建 http 请求(不同环境)
  • 支持 Promise API
  • 拦截请求和响应
  • 转换请求数据和响应数据
  • 取消请求
  • 自动转换 JSON 数据
  • 客户端支持防御 XSRF

navigator.sendBeacon() 方法可用于通过 HTTP POST 将少量数据 异步 传输到 Web 服务器。

它主要用于将统计数据发送到 Web 服务器,同时避免了用传统技术(如:XMLHttpRequest)发送分析数据的一些问题。

语法

navigator.sendBeacon(url);
navigator.sendBeacon(url, data);

参数

这个方法主要用于满足统计和诊断代码的需要,这些代码通常尝试在卸载(unload)文档之前向 Web 服务器发送数据。过早的发送数据可能导致错过收集数据的机会。然而,对于开发者来说保证在文档卸载期间发送数据一直是一个困难。因为用户代理通常会忽略在 unload 事件处理器中产生的异步 XMLHttpRequest

过去,为了解决这个问题,统计和诊断代码通常要在

  • 发起一个同步 XMLHttpRequest 来发送数据。
  • 创建一个 img,大部分用户代理会延迟卸载(unload)文档以加载图像。
  • 创建一个几秒的 no-op 循环。

上述的所有方法都会迫使用户代理延迟卸载文档,并使得下一个导航出现的更晚。下一个页面对于这种较差的载入表现无能为力。

这就是 sendBeacon() 方法存在的意义。使用 sendBeacon() 方法会使用户代理在有机会时异步地向服务器发送数据,同时不会延迟页面的卸载或影响下一导航的载入性能,这意味着:

  • 数据发送是可靠的。
  • 数据异步传输。
  • 不影响下一导航的载入。

数据是通过 HTTP POST 请求发送的

**Fetch 相比 XHR **

  1. 使用场景比较多,Service Worker 环境里也能用,相比 xhr 只能运行在渲染进程内
  2. 同源请求也可以自定义不带 cookie,某些服务不需要 cookie 场景下能少些流量
  3. 可自定义重定向场景,xhr 只能 follow
  4. 自定义 cache mode ,xhr 只能借助 response header(Cache-Control…等)
  5. 可自定义 referrer
  6. 原生支持,不需要额外装包。

劣势:

  • 劣势:

    1. 没有 timeout 事件(可以通过 race 封装实现流程控制,但这样不能中断连接;因为 abort 已经通过 AbortController 支持,也可以通过 abort 间接实现 timeout);

    2. 没有 progress 事件(上传、下载进度没有比较方便的实现方法);

tips:

fetch 可通过实验性的 abort 中断请求,

请求中断

XHR

var xhr = new XMLHttpRequest();

xhr.open("GET", "/your-endpoint", true);
xhr.send();

// 在某个时刻,你可以调用abort()来中断请求
xhr.abort();

当你调用abort()方法时,如果请求还在进行中,它会立即被停止。正在进行的任何网络活动都会被停止,而且 XHR 对象会立即停止所有的事件监听器(例如onloadonerror等)。

如果成功中断请求,abort事件会被派发,然后readystate会变为UNSENT

请注意,一旦请求被中断,XHR 对象就不能再被用于发起新的请求。如果你需要再次发起请求,你需要创建一个新的 XHR 对象。

axios

在 axios 中,你可以使用取消令牌(CancelToken)来中断一个请求。以下是一个示例:

var CancelToken = axios.CancelToken;
var source = CancelToken.source();

axios
.get("/user/12345", {
cancelToken: source.token,
})
.catch(function (thrown) {
if (axios.isCancel(thrown)) {
console.log("Request canceled", thrown.message);
} else {
// 处理错误
}
});

// 取消请求
source.cancel("Operation canceled by the user.");

在上面的代码中,axios.CancelToken.source()返回一个包含新的取消令牌和函数的对象。你可以把这个取消令牌传递给你的请求配置,然后在你需要取消请求的任何时候调用source.cancel()

当请求被取消时,axios promise 会被 reject,你可以在 catch 块中检查axios.isCancel(thrown)以确定是否请求被取消。

fetch

使用 AbortController 来中断一个请求。以下是一个示例:

// 创建一个 AbortController 实例
let controller = new AbortController();
let signal = controller.signal;

// 开始一个 fetch 请求
fetch("https://example.com", { signal })
.then((response) => response.text())
.then((text) => console.log(text))
.catch((err) => {
if (err.name === "AbortError") {
console.log("Fetch aborted");
} else {
console.error("Another error", err);
}
});

// 在需要中断请求的时候调用 abort 方法
controller.abort();

在上面的代码中,你创建了一个 AbortController 实例,并从中获取到了一个 signal。然后在你的 fetch 请求中,将这个 signal 传递给 fetch 请求的选项。

然后,当你需要中断这个请求的时候,你可以调用 controller.abort() 方法。这将会导致 fetch promise 被 reject,并且错误的 name 属性为 ‘AbortError’。你可以在 catch 块中检查这个属性,以确定是否请求被取消。

promise 可借助 promise.race 中断请求

利用这个特性,你可以创建一个延迟拒绝的 Promise,与你的请求 Promise 一起传递给Promise.race,以实现中断请求的功能。例如:

let delay = function (duration) {
return new Promise(function(resolve, reject) {
setTimeout(reject, duration);
});
};

let fetchSomething = function () {
// 这里应该是你的请求
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('请求结果');
}, 5000);
});
};

Promise.race([fetchSomething(), delay(3000)])
.then(function (result) {
// 请求在3秒内完成
console.log(result);
})
.catch(function (error) {
// 请求超时
console.error('请求超时');
});

在这个例子中,如果fetchSomething在 3 秒内完成,Promise.race会返回该请求的结果,否则delay会在 3 秒后拒绝,导致Promise.race被拒绝,这样就实现了请求的超时控制。