您的位置:首页 > 文旅 > 旅游 > 深圳万户网络技术有限公司_小制作怎么做_手机网络优化软件_seo项目优化案例分析文档

深圳万户网络技术有限公司_小制作怎么做_手机网络优化软件_seo项目优化案例分析文档

2024/12/23 2:15:45 来源:https://blog.csdn.net/qianyin925/article/details/143265754  浏览:    关键词:深圳万户网络技术有限公司_小制作怎么做_手机网络优化软件_seo项目优化案例分析文档
深圳万户网络技术有限公司_小制作怎么做_手机网络优化软件_seo项目优化案例分析文档

引言

Fetch API 提供了一个获取资源的接口(包括跨网络通信)。对于任何使用过 XMLHttpRequest 的开发者来说, 对于 Fetch 应该都能轻松上手, 而且新的 API 提供了更强大和灵活的功能集…

本文主要就是记录下, 在使用 Fetch 期间可能会碰到的几个小案例…

一、取消请求

在前端开发中, 取消请求是一个比较常见的需求了吧!!

下面举个场景, 比如我们要实现一个类似 google 一样的搜索提示下拉框, 下拉框内容是根据输入框内容查询出来的!! 当用户快速输入词条, 必然会高频的调用接口, 这时难免会出现先请求的接口响应速度比后请求的慢, 这样的话就有可能出现响应覆盖的问题!! 这里常规的解决办法有以下几种:

  1. 防抖: 用户快速地交互过程中, 只使用最后一次交互产生的数据, 然后再发起请求!
  2. 锁状态: 在上一个接口没有返回数据时, 交互状态一直处于 loading 的锁定状态
  3. 取消上一个请求: 在发起下一个请求前, 把之前的请求取消掉

防抖锁状态 虽然能解决问题, 但或多或少还是会影响用户的一个体验, 所以个人认为比较好的方案就是 取消上一个请求。下面将介绍如果在 Fetch 中如何取消请求!

Fetch 中如果需要中止未完成请求, 可使用 AbortController, AbortController 接口表示一个控制器对象, 允许你根据需要中止一个或多个 Web 请求

具体使用见下面代码:

  • 先创建了一个 AbortController 实例对象 controller
  • fetch 发起请求过程中, 设置 signal 参数, 让对应 fetch 请求和 AbortController 控制器进行一个绑定
  • 通过定时器, 在 1 秒后通过控制器的 abort() 方法来取消所有和控制器相互关联的请求
  • 最后我们可以在 .catch 中通过判断 Error 对象的 name 属性, 来检测到请求取消的行为
const controller = new AbortController();fetch("/user/12345", { signal: controller.signal }
).then(response => {console.log('请求成功');
}).catch(err => {if(err.name === "AbortError") {// 请求被手动取消} else {// 处理正常错误}
});// 1S 后手动取消请求
setTimeout(() => {controller.abort();
}, 1000)

二、读取流数据

想必你应该听说过 Server-Sent Events(SSE), 如果还不清楚可以看看我的这篇文章 《在 Koa 中基于 gpt-3.5 模型实现一个最基本的流式问答 DEMO》!!

本质上其实就是后端接口和前端建立了一个单向长连接, 然后后端不断的向前端推送流数据, 前端可通过 SSE 的方式来接收流数据!!

但实际上, 在 Fetch 中其实也是支持实时读取流数据的, 我们可以使用 response.body 属性。它是 ReadableStream 特殊对象, 它允许接口逐块(chunk)为前端提供 body。在 Streams API 规范中有对 ReadableStream 的详细描述!

如下代码所示:

  • await reader.read(): 调用的结果是一个具有两个属性的对象
  • done: 当读取完成时为 true, 否则为 false
  • value: 字节的类型化数组: Uint8Array
const handle = async () => {// 1. 请求接口const response = await fetch('http://127.0.0.1:4000/demo');const reader = response.body.getReader(); // 获取readerconst decoder = new TextDecoder(); // 文本解码器// 2. 循环取值while (true) {// 取值, value 是后端返回流信息, done 表示后端结束流的输出const { value, done } = await reader.read();if (done) break;// 打印值: 对 value 进行解码console.log('推送数据', decoder.decode(value));}
};handle();

三、获取下载文件长度

上文提到 Fetch 可以分片读取流数据, 那么如果我们能够知道要获取的资源大小或者长度, 那么我们就能够通过资源大小以及获取到的数据大小来计算出请求的进度

所以这里其实还需要后端配合, 需要将响应头 Content-Length 设置为资源的一个完整的长度, 这样前端就可以直接通过响应头 Content-Length 来拿到资源的完整长度, 从而计算出当前下载进度

// 1. 启动 fetch, 并获得一个 reader
let response = await fetch('https://api.github.com/repos/javascript-tutorial/en.javascript.info/commits?per_page=100');
const reader = response.body.getReader();// 2. 获得总长度(length)
const contentLength = +response.headers.get('Content-Length');// 3. 读取数据
let receivedLength = 0; // 当前接收到了这么多字节
let chunks = []; // 接收到的二进制块的数组(包括 body)while(true) {const {done, value} = await reader.read();if (done) {break;}chunks.push(value);receivedLength += value.length;console.log(`Received ${receivedLength} of ${contentLength}`)
}// 4. 将块连接到单个 Uint8Array
let chunksAll = new Uint8Array(receivedLength); // (4.1)
let position = 0;
for(let chunk of chunks) {chunksAll.set(chunk, position); // (4.2)position += chunk.length;
}// 5. 解码成字符串
let result = new TextDecoder("utf-8").decode(chunksAll);// 我们完成啦!
let commits = JSON.parse(result);
alert(commits[0].author.login);

四、上传文件进度条

到目前为止, fetch 方法无法跟踪 上传 进度。相关功能可以使用 XMLHttpRequest 来实现

使用 XMLHttpRequest 对象, 它提供了一个 progress 事件, 该事件在 上传数据时 会不断被触发, 并且在回调函数中我们可以获取当当前上传的一个进度, 具体参考 《MDN - 使用 XMLHttpRequest》

var oReq = new XMLHttpRequest();oReq.addEventListener("progress", updateProgress);
oReq.addEventListener("load", transferComplete);
oReq.addEventListener("error", transferFailed);
oReq.addEventListener("abort", transferCanceled);oReq.open();// ...// 服务端到客户端的传输进程(下载)
function updateProgress(oEvent) {if (oEvent.lengthComputable) {var percentComplete = (oEvent.loaded / oEvent.total) * 100;// ...} else {// 总大小未知时不能计算进程信息}
}function transferComplete(evt) {console.log("The transfer is complete.");
}function transferFailed(evt) {console.log("An error occurred while transferring the file.");
}function transferCanceled(evt) {console.log("The transfer has been canceled by the user.");
}

五、参考

  • Fetch: 下载进度
  • fetch 下载文件 + 显示进度
  • axios/fetch/XMLHttpRequest怎么取消请求

image

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com