javascript基础学习系列三百七十二:Uint8Array 转换为可读文本

文章介绍了如何使用异步函数和迭代器接口简化fetch操作,包括async/await处理read()方法,封装到Iterable和生成器函数中,以及利用ReadableStream进行内容操作和解码。重点讨论了处理不同大小和填充状态的Uint8Array块,以及双流技术的应用。
摘要由CSDN通过智能技术生成

异步函数非常适合这样的 fetch()操作。可以通过使用 async/await 将上面的递归调用打平:

fetch('https://fetch.spec.whatwg.org/') .then((response) => response.body) .then(async function(body) {
        let reader = body.getReader();
        while(true) {
          let { value, done } = await reader.read();
            if (done) {
              break;
}
            console.log(value);
          }
});
    // { value: Uint8Array{}, done: false }
    // { value: Uint8Array{}, done: false }
    // { value: Uint8Array{}, done: false }
    // ...

另外,read()方法也可以真接封装到 Iterable 接口中。因此就可以在 for-await-of 循环中方 便地实现这种转换:

fetch('https://fetch.spec.whatwg.org/') .then((response) => response.body) .then(async function(body) {
        let reader = body.getReader();
        let asyncIterable = {
          [Symbol.asyncIterator]() {
            return {
              next() {
                return reader.read();
              }
}; }
};
        for await (chunk of asyncIterable) {
          console.log(chunk);
}
});
    // { value: Uint8Array{}, done: false }
    // { value: Uint8Array{}, done: false }
    // { value: Uint8Array{}, done: false }
    // ...

通过将异步逻辑包装到一个生成器函数中,还可以进一步简化代码。而且,这个实现通过支持只读 取部分流也变得更稳健。如果流因为耗尽或错误而终止,读取器会释放锁,以允许不同的流读取器继续 操作:

   async function* streamGenerator(stream) {
      const reader = stream.getReader();
 
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        break;
}
      yield value;
    }
  } finally {
    reader.releaseLock();
} }
fetch('https://fetch.spec.whatwg.org/')
  .then((response) => response.body)
  .then(async function(body) {
for await (chunk of streamGenerator(body)) { console.log(chunk);
} });

要将 Uint8Array 转换为可读文本,可以将缓冲区传给 TextDecoder,返回转换后的值。通过设
置 stream: true,可以将之前的缓冲区保留在内存,从而让跨越两个块的内容能够被正确解码:
在这些例子中,当读取完 Uint8Array 块之后,浏览器会将其标记为可以被垃圾回收。对于需要在 不连续的内存中连续检查大量数据的情况,这样可以节省很多内存空间。

缓冲区的大小,以及浏览器是否等待缓冲区被填充后才将其推到流中,要根据 JavaScript 运行时的 实现。浏览器会控制等待分配的缓冲区被填满,同时会尽快将缓冲区数据(有时候可能未填充数据)发 送到流。
不同浏览器中分块大小可能不同,这取决于带宽和网络延迟。此外,浏览器如果决定不等待网络,
也可以将部分填充的缓冲区发送到流。最终,我们的代码要准备好处理以下情况:
 不同大小的 Uint8Array 块;
 部分填充的 Uint8Array 块;
 块到达的时间间隔不确定。
默认情况下,块是以 Uint8Array 格式抵达的。因为块的分割不会考虑编码,所以会出现某些值作
为多字节字符被分散到两个连续块中的情况。手动处理这些情况是很麻烦的,但很多时候可以使用 Encoding API 的可插拔方案。

Fetch API

  let decoder = new TextDecoder();
async function* streamGenerator(stream) {
  const reader = stream.getReader();
  try {
    while (true) {
      const { value, done } = await reader.read();
      if (done) {
        break;
}
}
    fetch('https://fetch.spec.whatwg.org/')
      .then((response) => response.body)
      .then(async function(body) {
for await (chunk of streamGenerator(body)) { console.log(decoder.decode(chunk, { stream: true }));
} });
    // <!doctype html><html lang="en"> ...
    // whether a <a data-link-type="dfn" href="#concept-header" ...
    // result to <var>rangeValue</var>. ...
    // ...

因为可以使用 ReadableStream 创建 Response 对象,所以就可以在读取流之后,将其通过管道 导入另一个流。然后在这个新流上再使用 Body 的方法,如 text()。这样就可以随着流的到达实时检 查和操作流内容。下面的代码展示了这种双流技术:

fetch('https://fetch.spec.whatwg.org/')
      .then((response) => response.body)
      .then((body) => {
        const reader = body.getReader();
// 创建第二个流
return new ReadableStream({
          async start(controller) {
            try {
              while (true) {
                const { value, done } = await reader.read();
                if (done) {
                  break;
}
// 将主体流的块推到第二个流
                controller.enqueue(value);
}
} finally {
              controller.close();
              reader.releaseLock();
            }
}
})
})
      .then((secondaryStream) => new Response(secondaryStream))
      .then(response => response.text())
      .then(console.log);
// <!doctype html><html lang="en"><head><meta charset="utf-8"> ...
  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值