文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

高效传输大的 JSON 数据,流式处理真香!

2024-11-29 22:43

关注

为什么使用 TextDecoder API

在处理 Web 应用中的二进制数据时,通常需要将这些数据转换为可读的字符串格式。TextDecoder 提供了一种高效且便捷的方法来实现这一点。

TextDecoder API 有以下特点:

如何使用 TextDecoder API

下面我们将介绍 TextDecoder API 的四种使用场景:

  1. 解码 ArrayBuffer 数据
  2. 解码不同编码的二进制数据
  3. 解码流式 JSON 数据
  4. 解码大 JSON 文件中的数据块

1.解码 ArrayBuffer 数据

// 创建一个包含 UTF-8 编码文本的 Uint8Array
const uint8Array = new Uint8Array([72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100]);

// 创建一个 TextDecoder 实例,默认使用 UTF-8 编码
const decoder = new TextDecoder('utf-8');

// 将 Uint8Array 解码为字符串
const decodedString = decoder.decode(uint8Array);

console.log(decodedString); // 输出 "Hello World"

2.解码不同编码的二进制数据

// 使用不同的编码创建 TextDecoder 实例
const utf16Decoder = new TextDecoder('utf-16');
const iso88591Decoder = new TextDecoder('iso-8859-1');

// 示例二进制数据
const utf16Array = new Uint16Array([0x0048, 0x0065, 0x006C, 0x006C, 0x006F]);
const iso88591Array = new Uint8Array([72, 101, 108, 108, 111]);

// 解码为字符串
const utf16String = utf16Decoder.decode(utf16Array);
const iso88591String = iso88591Decoder.decode(iso88591Array);

console.log(utf16String); // 输出 "Hello"
console.log(iso88591String); // 输出 "Hello"

3.解码流式 JSON 数据

首先,我们先来看一下效果:

图片

在以上的示例中,我们使用 Node.js 的 http 模块,快速搭建一个本地 SSE[2](Server-Sent Events)服务器。

server.js

const http = require("http");

const PORT = 3000;

const server = http.createServer((req, res) => {
  if (req.url === "/sse") {
    res.writeHead(200, {
      "Content-Type": "text/event-stream",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Headers":
        "Origin, X-Requested-With, Content-Type, Accept",
    });

    let id = 1;
    const interval = setInterval(() => {
      const data = {
        id: id,
        message: `This is message ${id}`,
        timestamp: +new Date(),
      };
      res.write(`data: ${JSON.stringify(data)}\n\n`);

      // 停止条件
      if (id == 5) {
        res.write("event: end\n");
        res.write("data: End of stream\n\n");
        clearInterval(interval);
        res.end();
      }

      id++;
    }, 1000);

    req.on("close", () => {
      clearInterval(interval);
    });
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.end("404 Not Found");
  }
});

server.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

需要注意的是,在 sse 接口中,我们设置 Content-Type 响应头的类型为: "text/event-stream",告诉客户端我们返回的是流式数据。

index.html

⚠️:访问 index.html 网页前,记得运行 node server.js 命令先启动 SSE 服务器。





    
    
    SSE & TextDecoder


    
    

client.js

document.addEventListener("DOMContentLoaded", () => {
  const messagesDiv = document.querySelector("#messages");
  const textDecoder = new TextDecoder("utf-8");

  fetch("http://localhost:3000/sse").then((response) => {
    const reader = response.body.getReader();
    return new ReadableStream({
      start(controller) {
        function push() {
          reader.read().then(({ done, value }) => {
            if (done) {
              controller.close();
              return;
            }

            const chunk = textDecoder.decode(value, { stream: true });
            const lines = chunk.split("\n");

            for (const line of lines) {
              if (line.startsWith("data: ")) {
                const json = line.slice(6);
                const data = JSON.parse(json);
                const p = document.createElement("p");
                p.textContent = `ID: ${data.id}, Message: ${data.message}, Timestamp: ${data.timestamp}`;
                messagesDiv.appendChild(p);
              } else if (line.startsWith("event: end")) {
                const p = document.createElement("p");
                p.textContent = "End of stream";
                messagesDiv.appendChild(p);
                return;
              }
            }

            push();
          });
        }

        push();
      },
    });
  });
});

SSE 事件流是一个简单的文本数据流,文本是使用 UTF-8 格式的编码。所以,在创建 textDecoder 对象时,我们需要设置它的编码为 utf-8。有了 textDecoder 对象后,调用它提供的 decode 方法就可以进行解码了。

4.解码大 JSON 文件中的数据块

当遇到传输大 JSON 数据的时候,如果使用传统的方式,我们需要接收完整的 JSON 数据后,才能开始进行数据处理,这对用户体验会造成一定的影响。为了解决这个问题,我们可以使用一些现成的 JSON Stream 解析库。比如,@streamparser/json[3],该库内部也使用了本文介绍的 TextDecoder API。

下面,我们先来看一下效果:

上图中输出的 JSON 数据来自以下的 large.json 文件。我们对该文件按照 0.5KB 的大小进行切割,然后每个 500ms 发送下一个数据块。利用 @streamparser/json 这个库,我们实现了解析 JSON 数据流(JSON Chunk)的功能。

large.json

[
  {},
  {
    "image": [
      {
        "shape": "rect",
        "fill": "#333",
        "stroke": "#999",
        "x": 0.5e1,
        "y": 0.5,
        "z": 0.8,
        "w": 0.5e5,
        "u": 2e10,
        "foo": 2e1,
        "bar": 2,
        "width": 47,
        "height": 47
      }
    ],
    "corners": { "1": true, "3": true, "7": true, "9": true }
  },
 ...
]

json-server.js

const http = require("http");
const { join } = require("path");
const { readFileSync } = require("fs");

const PORT = 3000;

const largeJson = readFileSync(join(__dirname, "large.json")).toString();

const server = http.createServer((req, res) => {
  if (req.url === "/stream-json") {
    res.writeHead(200, {
      "Content-Type": "application/json",
      "Cache-Control": "no-cache",
      Connection: "keep-alive",
      "Access-Control-Allow-Origin": "*",
      "Access-Control-Allow-Headers":
        "Origin, X-Requested-With, Content-Type, Accept",
    });

    const CHUNK_SIZE = 512; // 每块 0.5KB
    let position = 0;

    const interval = setInterval(() => {
      const chunk = largeJson.slice(position, position + CHUNK_SIZE);
      res.write(chunk);
      position += CHUNK_SIZE;

      if (position >= largeJson.length) {
        clearInterval(interval);
        res.end();
      }
    }, 500); // 每 500ms 发送一块数据

    req.on("close", () => {
      clearInterval(interval);
    });
  } else {
    res.writeHead(404, { "Content-Type": "text/plain" });
    res.end("404 Not Found");
  }
});

server.listen(PORT, () => {
  console.log(`Server is running on http://localhost:${PORT}`);
});

stream-json.html



  
    
    
    Stream JSON
  
  
    
    

@streamparser/json 这个库还有其他的用法,如果你感兴趣的话,可以看一下它的使用文档。

参考资料

[1]TextDecoder: https://developer.mozilla.org/zh-CN/docs/Web/API/TextDecoder

[2]SSE: https://developer.mozilla.org/zh-CN/docs/Web/API/Server-sent_events

[3]@streamparser/json: https://www.npmjs.com/package/@streamparser/json

来源:全栈修仙之路内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯