Efficient data handling with the Streams API title.  A vibrant gradient with a JavaScript logo in the bottom-left corner and a graphic representing data being processed in a browser in the top-right corner.
赞助

使用 Streams API 高效处理数据

阅读时间 6 分钟

Streams API 使您能够访问通过网络接收的数据流,并在网页上使用 JavaScript 进行处理。以前,如果您想处理通过网络获取的数据,您必须先下载整个资源,等待其转换为您可以处理的格式,然后再开始处理。使用 Streams API,您可以在原始数据到达时使用 JavaScript 进行处理,这使其非常适合处理连续数据源、实时转换数据、在收到所需数据时取消流等等。

在本文中,我们将探讨 Streams API 的概念、用法和实际应用。我们还将通过一个实际示例,构建一个小应用程序,该应用程序使用该 API 来转换数据流。

理解 Streams API

Streams API 提供了一种在 JavaScript 中处理流式数据的标准方法。它允许您逐块处理数据,对于处理 Web 应用程序中的大型资源或实时数据非常高效。您应该了解 Streams API 中的这些关键概念:

数据块 (Chunks)

数据以称为数据块的片段顺序读取。一个数据块可以是一个字节,也可以是较大的内容,例如特定大小的 类型化数组。单个流可以包含不同大小和类型的数据块。

背压

API 自动管理背压,确保快速生产者不会压倒慢速消费者。这通过内部队列机制来处理。

管道 (Piping)

API 提供诸如 pipeThrough()pipeTo() 之类的方法来连接流,从而允许对数据进行链式处理。

API 包含以下针对不同类型流的抽象:

ReadableStream

表示可以从中读取数据的源。它可以从各种源创建,例如 fetch 响应或文件输入。

WritableStream

表示可以向其中写入数据的目标。可用于写入文件或将数据发送到服务器等任务。

TransformStream

允许在数据从可读流传递到可写流时修改数据。适用于压缩或加密等任务。

构建 Node.js 应用程序

首先,请按照我们上一篇文章 在 Vultr 上部署服务器 部分所述的步骤部署服务器。接下来,通过 SSH 访问服务器终端,并为我们的 Web 应用程序设置项目。

我们将使用 Nano 文本编辑器在服务器上创建和编辑我们的项目文件。您可以在 快捷键备忘单 中查找使用 Nano 的帮助。我们还将使用 Uncomplicated Firewall (UFW) 来控制允许进出服务器的流量。在我们的应用程序中,Node.js 服务于应用程序的索引,并使用 http-server 运行应用程序。像 Python 和 Apache 这样的服务器也可以达到类似的效果。我们使用 UFW 启用端口 8000 的入站流量。

  1. 创建一个项目目录,并进入该目录。

    bash
    mkdir streaming-app && cd streaming-app
    
  2. 初始化一个 Node.js 项目。

    bash
    npm init -y
    
  3. 安装 HTTP 服务器。

    bash
    npm install http-server
    
  4. 创建一个 HTML 文件。

    bash
    nano index.html
    
  5. 将以下代码复制并粘贴到 index.html 文件中。

    html
    <!doctype html>
    <html lang="en">
      <head>
        <meta charset="UTF-8" />
        <meta name="viewport" content="width=device-width, initial-scale=1.0" />
        <title>File Stream Transformer</title>
      </head>
      <body>
        <h1>File Stream Transformer</h1>
        <button id="loadFileButton">Load and Transform File</button>
        <br />
        <h2>Transformed Content:</h2>
        <pre id="outputText"></pre>
    
        <script src="app.js"></script>
      </body>
    </html>
    
  6. 保存并退出文件。

  7. 在项目目录中创建一个文本文件 textfile.txt,并提供一些示例文本。您可以方便地使用 此文本文件 中的内容。

创建示例 Streams API 应用

  1. 在 streaming-app 目录中,创建一个 JavaScript 文件。

    bash
    nano app.js
    
  2. 将以下 JavaScript 代码复制并粘贴到 app.js 中。

    js
    document.addEventListener("DOMContentLoaded", initializeApp);
    
    function initializeApp() {
      const loadFileButton = document.getElementById("loadFileButton");
      const outputText = document.getElementById("outputText");
    
      loadFileButton.addEventListener("click", () =>
        fetchAndTransformFile(outputText),
      );
    }
    
    async function fetchAndTransformFile(outputElement) {
      clearOutput(outputElement);
    
      try {
        const response = await fetch("textfile.txt");
        const readableStream = response.body;
        const transformStream = createTransformStream();
        const writableStream = createWritableStream(outputElement);
    
        await readableStream.pipeThrough(transformStream).pipeTo(writableStream);
    
        console.log("File stream processing completed");
      } catch (error) {
        handleError(error, outputElement);
      }
    }
    
    function createTransformStream() {
      return new TransformStream({
        transform(chunk, controller) {
          const text = new TextDecoder().decode(chunk);
          const upperCaseChunk = text.toUpperCase();
          controller.enqueue(new TextEncoder().encode(upperCaseChunk));
        },
      });
    }
    
    function createWritableStream(outputElement) {
      return new WritableStream({
        write(chunk) {
          const text = new TextDecoder().decode(chunk);
          outputElement.textContent += text;
        },
      });
    }
    
    function clearOutput(outputElement) {
      outputElement.textContent = "";
      outputElement.style.color = "black";
    }
    
    function handleError(error, outputElement) {
      console.error("Error during stream processing:", error);
      outputElement.textContent = `An error occurred: ${error.message}`;
      outputElement.style.color = "red";
    }
    
  3. 保存并退出文件。

  4. 允许连接到端口 8080。

    bash
    ufw allow 8080
    
  5. 启动文件服务器。

    bash
    npx http-server
    
  6. 访问应用程序 URL http://<server-ip>:8080,然后点击 加载并转换 按钮。您将看到整个文本文件被获取并转换为大写字符。

当点击 加载并转换 按钮时,fetchAndTransformFile() 函数从服务器的文件系统中获取 textfile.txt。服务器以 ReadableStream 的形式响应数据,这使得文件可以分块处理。在客户端,这个 ReadableStream 通过一个 TransformStream 进行管道传输,该流将每个文本块转换为大写。然后,转换后的数据块通过 WritableStream 进行管道传输,该流将结果文本附加到 HTML 元素以进行显示。这表明了 Streams API 如何用于获取文件,以及在浏览器获取数据时对其进行处理、转换和显示,而不是在内存中对整个文件执行操作。

实际用例和示例

  1. 在视频流平台中
    • 用例:高效处理和传输大型视频文件。
    • 示例:视频流服务可以使用 Streams API 将大型视频文件分解成更小的块,进行处理(例如,应用滤镜或压缩),然后逐步传输给用户。这可以实现更流畅的播放并减少初始加载时间。
  2. 在数据可视化应用程序中
    • 用例:实时处理和可视化大型数据集或连续数据流。
    • 示例:金融仪表板可以使用 Streams API 实时处理市场数据。随着新数据的到来,它可以被转换、过滤并立即显示在图表或图形上,从而实现实时更新,而不会压垮浏览器的资源。
  3. 在文件上传/下载系统中
    • 用例:处理带有进度跟踪和实时处理的大文件传输。
    • 示例:云存储服务可以使用 Streams API 上传大文件。文件可以作为流读取,实时压缩或加密,并分块发送到服务器。这使得能够进行进度跟踪、暂停和恢复传输,并高效地利用内存,特别是对于非常大的文件。

总结

在本文中,我们深入探讨了 Streams API 的概念、用法和实际实现。我们开发了一个基本应用程序,演示了如何使用 Streams API 获取和转换数据。通过这个实践示例,我们学习了如何读取、写入和操作数据流。我们希望这将激发您创建高效、响应迅速的现代 Web 应用程序。

学习此 API 的一些好的后续步骤是执行更复杂的处理。您可以查看 MDN Streams API 示例之一,它与此项目非常相似,但它手动循环数据块,并在每个新数据块到达时将其记录到控制台。其他的 示例 展示了使用此 API 的不同方法,而 取消 fetch 演示则展示了当客户端收到所需数据时如何停止进行中的网络操作。

这是一篇由 Vultr 赞助的文章。Vultr 是全球最大的私营云计算平台。Vultr 是开发者的首选,已为 185 个国家/地区的 150 万多客户提供了灵活、可扩展、全球化的云计算、云 GPU、裸金属和云存储解决方案。了解更多关于 Vultr 的信息。