目录
1. 流,是什么?
2. 流,的具体使用场景
3. 流的分类
4. 数据模式和缓存区
5. 可读流
6. 可写流
首页 web前端 js教程 聊聊Nodejs中的核心模块:stream流模块(看看如何使用)

聊聊Nodejs中的核心模块:stream流模块(看看如何使用)

Dec 20, 2021 am 11:13 AM
nodejs stream流 模块

本篇文章带大家详细理解一下Nodejs中的stream流模块,介绍一下stream流概念及用法,希望对大家有所帮助!

聊聊Nodejs中的核心模块:stream流模块(看看如何使用)

stream流模块,是Node中非常核心的一个模块,其它模块如fs、http等都基于流stream模块的实例。

而对于大多前端小白在刚入门Node的学习过程中,对于流的概念及使用还是不太好清晰的理解,因为在前端的工作中似乎很少有过关于"流"处理相关的应用。

1. 流,是什么?

单纯“流”这个字,我们很容易产生水流,流动等的概念。

官方定义:流,是用于在 Node.js 中处理流数据的抽象接口

从官方的定义中,我们可以看出:

  • 流,是Node提供的一种处理数据的工具
  • 流,是Node中的一种抽象接口

准确的理解,流,可以理解为数据流,它是一种用来传输数据的手段,在一个应用程序中,流,是一种有序的,有起点和终点的数据流。

造成我们对stream流不太好的理解的主要原因就是,它是一种抽象的概念。

2. 流,的具体使用场景

为了让我们能够清楚的理解stream模块,我们首先来以具体的应用场景来说明stream模块有哪些实际应用之处。

stream流,在Node中主要应用在大量数据处理的需求上,如fs对大文件的读取和写入、http请求响应、文件的压缩、数据的加密/解密等应用。

1.png

我们以上面的图片说明流的使用,水桶可以理解为数据源,水池可以理解为数据目标,中间连接的管道,我们可以理解为数据流,通过数据流管道,数据从数据源流向数据目标。

3. 流的分类

在Node中,流被分为4类:可读流,可写流,双工流,转换流。

  • Writable: 可以写入数据的流
  • Readable: 可以从中读取数据的流
  • DuplexReadable 和 Writable 的流
  • Transform: 可以在写入和读取数据时修改或转换数据的 Duplex 流

所有的流都是 EventEmitter 的实例。即我们可以通过事件机制监听数据流的变化。

4. 数据模式和缓存区

在深入学习4类流的具体使用之前,我们需要理解两个概念数据模式缓存区,有助于我们在接下来流的学习中更好的理解。

4.1 数据模式

Node.js API 创建的所有流都只对字符串和 Buffer(或 Uint8Array)对象进行操作。

4.2 缓存区

Writable和 Readable 流都将数据存储在内部缓冲区(buffer)中。

可缓冲的数据量取决于传给流的构造函数的 highWaterMark 选项, 对于普通的流,highWaterMark 选项指定字节的总数;对于在对象模式下操作的流,highWaterMark选项指定对象的总数。

highWaterMark 选项是阈值,而不是限制:它规定了流在停止请求更多数据之前缓冲的数据量。

当实现调用 stream.push(chunk) 时,数据缓存在 Readable 流中。 如果流的消费者没有调用 stream.read(),则数据会一直驻留在内部队列中,直到被消费。

一旦内部读取缓冲区的总大小达到 highWaterMark 指定的阈值,则流将暂时停止从底层资源读取数据,直到可以消费当前缓冲的数据

当重复调用 writable.write(chunk) 方法时,数据会缓存在 Writable 流中。

5. 可读流

5.1 流读取的流动与暂停

Readable 流以两种模式之一有效地运行:流动和暂停。

  • 流动模式:从系统底层读取数据并push()到缓存区,达到highWaterMark后 push() 会返回 false,资源停止流向缓存区,并触发data事件消费数据。

  • 暂停模式:所有的Readable流都是以Paused暂停模式开始,必须显式调用stream.read()方法来从流中读取数据。每一次数据达到缓存区都会触发一次 readable 事件,也就是每一次 push() 都会触发 readable。

  • 暂停模式切换到流动模式的方式:

    • 添加data事件句柄
    • 调用stream.resume()方法
    • 调用stream.pipe()方法将数据发送到 Writable
  • 流动模式切换到暂停模式的方式:

    • 如果没有管道目标,则通过调用 stream.pause() 方法。
    • 如果有管道目标,则删除所有管道目标。 可以通过调用 stream.unpipe()方法删除多个管道目标。

5.2 可读流常用示例

import path from 'path';
import fs, { read } from 'fs';

const filePath = path.join(path.resolve(), 'files', 'text.txt');

const readable = fs.createReadStream(filePath);
// 如果使用 readable.setEncoding() 方法为流指定了默认编码,则监听器回调将把数据块作为字符串传入;否则数据将作为 Buffer 传入。
readable.setEncoding('utf8');
let str = '';

readable.on('open', (fd) => {
  console.log('开始读取文件')
})
// 每当流将数据块的所有权移交给消费者时,则会触发 'data' 事件
readable.on('data', (data) => {
  str += data;
  console.log('读取到数据')
})
// 方法将导致处于流动模式的流停止触发 'data' 事件,切换到暂停模式。 任何可用的数据都将保留在内部缓冲区中。
readable.pause();
// 方法使被显式暂停的 Readable 流恢复触发 'data' 事件,将流切换到流动模式。
readable.resume();
// 当调用 stream.pause() 并且 readableFlowing 不是 false 时,则会触发 'pause' 事件。
readable.on('pause', () => {
  console.log('读取暂停')
})
// 当调用 stream.resume() 并且 readableFlowing 不是 true 时,则会触发 'resume' 事件。
readable.on('resume', () => {
  console.log('重新流动')
})
// 当流中没有更多数据可供消费时,则会触发 'end' 事件。
readable.on('end', () => {
  console.log('文件读取完毕');
})
// 当流及其任何底层资源(例如文件描述符)已关闭时,则会触发 'close' 事件。
readable.on('close', () => {
  console.log('关闭文件读取')
})
// 将 destWritable 流绑定到 readable,使其自动切换到流动模式并将其所有数据推送到绑定的 Writable。 数据流将被自动管理
readable.pipe(destWriteable)
// 如果底层流由于底层内部故障而无法生成数据,或者当流实现尝试推送无效数据块时,可能会发生这种情况。
readable.on('error', (err) => {
  console.log(err)
  console.log('文件读取发生错误')
})
登录后复制

6. 可写流

6.1 可写流的流动与暂停

writeable流 与 readable流 是比较相似的,数据流过来的时候,会直接写入到缓存区,当写入速度比较缓慢或者写入暂停时,数据流会在缓存区缓存起来;

当生产者写入速度过快,把队列池装满了之后,就会出现「背压」,这个时候是需要告诉生产者暂停生产的,当队列释放之后,writable流 会给生产者发送一个 drain 消息,让它恢复生产。

6.2 可写流示例

import path from 'path';
import fs, { read } from 'fs';

const filePath = path.join(path.resolve(), 'files', 'text.txt');
const copyFile = path.join(path.resolve(), 'files', 'copy.txt');

let str = '';
// 创建可读流
const readable = fs.createReadStream(filePath);
// 如果使用 readable.setEncoding() 方法为流指定了默认编码
readable.setEncoding('utf8');

// 创建可写流
const wirteable = fs.createWriteStream(copyFile);
// 编码
wirteable.setDefaultEncoding('utf8');

readable.on('open', (fd) => {
  console.log('开始读取文件')
})
// 每当流将数据块的所有权移交给消费者时,则会触发 'data' 事件
readable.on('data', (data) => {
  str += data;
  console.log('读取到数据');

  // 写入
  wirteable.write(data, 'utf8');
})

wirteable.on('open', () => {
  console.log('开始写入数据')
})
// 如果对 stream.write(chunk) 的调用返回 false,则 'drain' 事件将在适合继续将数据写入流时触发。
// 即生产数据的速度大于写入速度,缓存区装满之后,会暂停生产着从底层读取数据
// writeable缓存区释放之后,会发送一个drain事件让生产者继续读取
wirteable.on('drain', () => {
  console.log('继续写入')
})
// 在调用 stream.end() 方法之后,并且所有数据都已刷新到底层系统,则触发 'finish' 事件。
wirteable.on('finish', () => {
  console.log('数据写入完毕')
})

readable.on('end', () => {
  // 数据读取完毕通知可写流
  wirteable.end()
})
// 当在可读流上调用 stream.pipe() 方法将此可写流添加到其目标集时,则触发 'pipe' 事件。
// readable.pipe(destWriteable)
wirteable.on('pipe', () => {
  console.log('管道流创建')
})

wirteable.on('error', () => {
  console.log('数据写入发生错误')
})
登录后复制

更多node相关知识,请访问:nodejs 教程!!

以上是聊聊Nodejs中的核心模块:stream流模块(看看如何使用)的详细内容。更多信息请关注PHP中文网其他相关文章!

本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

nodejs和vuejs区别 nodejs和vuejs区别 Apr 21, 2024 am 04:17 AM

Node.js 是一种服务器端 JavaScript 运行时,而 Vue.js 是一个客户端 JavaScript 框架,用于创建交互式用户界面。Node.js 用于服务器端开发,如后端服务 API 开发和数据处理,而 Vue.js 用于客户端开发,如单页面应用程序和响应式用户界面。

nodejs是后端框架吗 nodejs是后端框架吗 Apr 21, 2024 am 05:09 AM

Node.js 可作为后端框架使用,因为它提供高性能、可扩展性、跨平台支持、丰富的生态系统和易于开发等功能。

nodejs怎么连接mysql数据库 nodejs怎么连接mysql数据库 Apr 21, 2024 am 06:13 AM

要连接 MySQL 数据库,需要遵循以下步骤:安装 mysql2 驱动程序。使用 mysql2.createConnection() 创建连接对象,其中包含主机地址、端口、用户名、密码和数据库名称。使用 connection.query() 执行查询。最后使用 connection.end() 结束连接。

nodejs中的全局变量有哪些 nodejs中的全局变量有哪些 Apr 21, 2024 am 04:54 AM

Node.js 中存在以下全局变量:全局对象:global核心模块:process、console、require运行时环境变量:__dirname、__filename、__line、__column常量:undefined、null、NaN、Infinity、-Infinity

nodejs安装目录里的npm与npm.cmd文件有什么区别 nodejs安装目录里的npm与npm.cmd文件有什么区别 Apr 21, 2024 am 05:18 AM

Node.js 安装目录中有两个与 npm 相关的文件:npm 和 npm.cmd,区别如下:扩展名不同:npm 是可执行文件,npm.cmd 是命令窗口快捷方式。Windows 用户:npm.cmd 可以在命令提示符下使用,npm 只能从命令行运行。兼容性:npm.cmd 特定于 Windows 系统,npm 跨平台可用。使用建议:Windows 用户使用 npm.cmd,其他操作系统使用 npm。

nodejs和java的差别大吗 nodejs和java的差别大吗 Apr 21, 2024 am 06:12 AM

Node.js 和 Java 的主要差异在于设计和特性:事件驱动与线程驱动:Node.js 基于事件驱动,Java 基于线程驱动。单线程与多线程:Node.js 使用单线程事件循环,Java 使用多线程架构。运行时环境:Node.js 在 V8 JavaScript 引擎上运行,而 Java 在 JVM 上运行。语法:Node.js 使用 JavaScript 语法,而 Java 使用 Java 语法。用途:Node.js 适用于 I/O 密集型任务,而 Java 适用于大型企业应用程序。

nodejs是后端开发语言吗 nodejs是后端开发语言吗 Apr 21, 2024 am 05:09 AM

是的,Node.js 是一种后端开发语言。它用于后端开发,包括处理服务器端业务逻辑、管理数据库连接和提供 API。

nodejs和java选哪个 nodejs和java选哪个 Apr 21, 2024 am 04:40 AM

Node.js 和 Java 在 Web 开发中各有优劣,具体选择取决于项目要求。Node.js 擅长实时应用程序、快速开发和微服务架构,而 Java 则在企业级支持、性能和安全性方面占优。

See all articles