使用 Streams API 进行高效的数据处理

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

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

了解 Streams API

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

数据以块(称为“块”)的形式按顺序读取。一个块可以是一个字节,也可以是更大的字节,例如特定大小的类型化数组。单个流可以包含不同大小和类型的块。

背压

该 API 自动管理背压,确保快速生产者不会压垮慢速消费者。这通过内部排队机制实现。

管道

API 提供了像pipeThrough()和这样的方法pipeTo()来连接流,从而允许链式处理数据。

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

ReadableStream

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

WritableStream

表示可以写入数据的目标位置。它可用于执行写入文件或向服务器发送数据等任务。

TransformStream

允许在数据从可读流传递到可写流时对其进行修改。这对于压缩或加密等任务非常有用。

构建 Node 应用程序

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

我们将使用Nano文本编辑器在服务器上创建和编辑项目文件。您可以查看快捷方式速查表,获取使用 Nano 的帮助。我们还将使用简易防火墙 (UFW)来控制允许进出服务器的流量。在我们的应用程序中,Node.js 提供应用程序的索引,并使用 运行该应用程序。Python 和Apachehttp-server等服务器也可以实现类似的效果。我们使用 UFW 允许通过端口 8000 传入流量。

  1. 创建一个项目目录并导航到该目录。
mkdir streaming-app && cd streaming-app
  1. 初始化一个 Node.js 项目。
  2. 安装 HTTP 服务器。
  3. 创建一个 HTML 文件。
  4. 将以下代码复制并粘贴到 index.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>
  1. 保存并退出文件。
  2. 在项目目录中创建一个文本文件,并提供一些示例文本。为了方便起见,您可以使用此文本文件textfile.txt的内容。

创建示例 Streams API 应用

  1. 在 streaming-app 目录中,创建一个 JavaScript 文件。
  2. 将下面的 JavaScript 代码复制并粘贴到 app.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";
}
  1. 保存并退出文件。
  2. 允许传入连接到端口 8080。
  3. 启动文件服务器。
  4. 访问应用程序 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 的不同方法,而“取消获取”演示则展示了如何在客户端收到所需数据后停止正在进行的网络操作。