前端较大数据传输优化方案(上)

122 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第13天,点击查看活动详情

前言

今天刷抖音看到一个与前端海量数据下载优化相关的问题(在大数据资源请求的时候,前端如果等待所有数据加载完,那么页面从请求到最终呈现内容,会有很长一段的空白期,如何优化响应速度呢,这就需要我们对响应数据做切片处理了),刚好学习了顺便对客户端请求数据的相关知识简单做了下总结复习

关于 Fetch

mdn文档:使用 Fetch - Web API 接口参考 | MDN (mozilla.org)

Fetch API 提供了一个 JavaScript 接口,用于访问和操纵 HTTP 管道的一些具体部分,例如请求和响应。它还提供了一个全局 fetch()方法,该方法提供了一种简单,合理的方式来跨网络异步获取资源

视频的内容是基于 fetch 展开做讲解的,这里我们也一样,先用 fetch 为案例降解,后续用 axios 以同样的思路再做一遍

首先我们看一下官网提供的一段代码

fetch('http://example.com/movies.json')
  .then(response => response.json())
  .then(data => console.log(data))

这里我们发现 fetch 发送请求时里边有 2 个 then,有的同学可能会有疑问,毕竟现在大部分项目使用的请求库都是 axios ,实际上 axios 也有这两个过程,只不过 axios 在内部把第一步 .json()或者.text() 数据转化的过程处理掉了,直接返回了我们处理后的结果

关于请求过程

2022-12-03 11 37 02

前面提到,在请求中第一个异步回调有两个数据处理的方法 json()和text() ,而这些方法的调用都有一个前提,就是必须等待请求头 header 传输完成后才可以调用

而后一个回调则是需要等待整个body传输完成后触发,这就意味着,如果body数据很大的话,那么等待响应就需要很长的时间

优化思路

既然等待整个body传输完再响应需要花很长时间,那么我们能不能在body传输的过程中就取到数据呢?就是传输一点用一点(即分片),答案是可以的,那么具体怎么做呢,请看下面

优化方法

fetch 方法在它的第一个响应体中提供了一个方法 getReader ,可以获取一个观察加载进度的对象,这个对象上又提供了一个read方法,可以异步的获取当前读取的数据内容(value 字节数组)和加载状态(done,未加载完成时为false,全部加载完成时为true),我们可以根据这个 done 的状态做一个递归,直到加载完成时一直去读取当前已加载好的数据进行处理

TextDecoder 文本解码器,用来处理文本数据

async function loadBody (url) {
    const res = await fetch(url)
    const reader = await res.body.getReader()
    let flag = false
​
    while(!flag) {
        const { value, done } = await reader.read()
        flag = done
        const decoder = new TextDecoder() // 文本解码器
        decoder.decode(value)
        const text = decoder.decode(value)
        console.log(text);
    }
}

现在我们拿一个本地 txt 文件,在浏览器慢速3G模式下调用一下上面的方法看看效果

2022-12-03 22 27 09

我们发现数据已经可以按照我们的期望做到分段加载了

但是细心的同学会发现现在还有一点小瑕疵,就是在切分点,由于字节的截取,很有可能在还原时造成乱码,这时就需要我们对这些切割点做特殊处理了,关于切割点如何优化处理,还有使用 axios 时如何分片,我们会在下一节在做详细讲解,敬请关注