JavaScript 中的 Stream API 04(转换流 TransformStream 等 API)

2024-08-31 13:04

本文主要是介绍JavaScript 中的 Stream API 04(转换流 TransformStream 等 API),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

Stream API

转换流 API

一个转换流接收所有的分块将其转换为 Uint8Array,上面可读流中的 value 也为该 Uint8Array 格式

TransformStream

TransformStream 是 Web Streams API 的一部分,它允许你通过提供一个转换函数来创建一个可写和可读的流对 → 这个转换函数接收来自上游的数据块(chunks),执行某些操作(如转换、过滤等),然后将结果数据块发送到下游 → 链式管道传输(pipe chain)转换流概念的具体实现

主要用途:

  • 转换数据: 在数据从源流向目的地的过程中对数据进行处理
  • 保持背压: 当下游消费数据的速度跟不上上游生产数据的速度时,能够自动暂停上游的写入操作,直到下游准备好继续接收数据

TransformStream 转换流实例对象的创建: new TransformStream(transformer, writableStrategy, readableStrategy)

  • transformer(可选): 该配置对象下面的每一个方法中都包含一个 controller(TransformStreamDefaultController 实例对象)参数

    • start(controller):

      • 该方法会在 TransformStream 实例对象被构建时来调用
      • 通常用于 TransformStreamDefaultController.equeue 将块压入流的队列中
    • transform(chunk,controller):

      • 当一个数据块(chunk)被写入到 WritableStream 端时,transform 函数会被调用,我们可以在该函数中对 chunk 做一些转换(一些自定义操作,开发者决定)后在通过 controller 中的 enqueue 压入队列

      • 即我们可以理解为一个 chunk 在被写入可写流之前,我们可以在该方法中先对 chunk 进行一些自定义的操作(转换),在将 chunk 压入到对应流的队列中(也可以理解为是一个拦截器)

      • {// -- 如 ↓: 当一个 chunk 被写入到可写流时,就会调用该函数,我们可以该函数对 chunk 进行一些转换等操作,如下示例转换成大小字符transform(chunk, controller) {controller.enqueue(chunk.toUpperCase()); }
        }
        // 这个转换流可以被用于管道操作中,如将文本数据从一种格式转换为另一种格式
        
    • flush(controller):

      • 当所有数据块都已经被写入到 WritableStream 端时,调用该方法且会关闭可写流
      • 可以理解为当已将所有数据写入后,调用了 writer 中的 close 关闭可写流的写入时触发该函数
  • writableStrategy(可选): 可写流的策略配置对象,具体参数与上面可读流一样,略...

  • readableStrategy(可选): 可读流的策略配置对象,具体参数与上面可读流一样,略...

实例属性: 转换流实例对象上只有两个属性,分别对应 ReadableStream 和 WritableStream 实例对象

  • readable: 返回当前转换流中的 ReadableStream 可读流实例对象
  • writable: 返回当前转换流中的 WritableStream 可写流实例对象

基本使用示例:

  • const transfer = new TransformStream({ // -- 1. 创建一个转换流start(controller) {console.log("init transform stream")},transform(chunk, controller) { // -- 2. 当一个 chunk 即将被写入到可写流中时,就会触发该方法 → 我们可以在 chunk 写入前在该方法中对 chunk 进行一些转换等操作 → 如下示例// -- 如下: 这里先将 chunk 转换成大写(可写流需写入字符),转换成大写后再通过 controller.enqueue 将其压入对应的队列中(使用该新的 chunk 进行写入可写流中)const chunkTransformed = chunk.toUpperCase()controller.enqueue(chunkTransformed)},flush(controller) {  // -- 3. 当所有数据块都写入完时(即调用 writer.close() 关闭可写流时),触发该方法 → 可在该方法中做一些清除操作等console.log("flush")controller.terminate() // -- 当流已经全部处理完时,通过该方法来结束流的处理过程(关闭流)}
    })
    
  • // -- 4. 通过转换流 TransformStream 实例对象上的 readable 和 writer 属性获取对应的可读流与可写流对象
    const readable = transfer.readable
    const writable = transfer.writable// -- 5. 通过 readable 和 writable,获取对应的读取器 reader 与写入器 writer → 当然也可以直接通直接获取(如: transfer.readable.getReader),这里为了每一步都清除一些,所以就逐步来获取
    const reader = readable.getReader()
    const writer = writable.getWriter()
    
  • // -- 6. 当 desiredSize 为正数时(无需背压),在里面模拟服务服务器返回流数据进行写入
    writer.ready.then(() => {writer.write("Kong")// -- 通过 setTimeout 默认流数据的请求setTimeout(() => writer.write("Xiang"), 200)setTimeout(() => writer.write("Hunag"), 400)setTimeout(() => writer.write("Xiao"), 600)setTimeout(() => {writer.write("Kong")writer.close() // -- 当所有数据都写入完成后,关闭可写流(如果不关闭,可读流在读取是对应的 done 属性将一直为 false,同理也不会触发上面转换流中的 flush 方法)}, 800)
    }).catch(err => {console.log("写入失败");
    })
    
  • // -- 7. 通过 reader 读取流中所有的数据块
    const read = () => {reader.read().then(({ value, done }) => { // -- 读取流中的每一个数据块if (done) { // -- 当流中所有数据块都读取完毕后,设置提示并返回(反之,在下面递归读取数据块)console.log("Stream readed completed")return}console.log(value) // -- 打印当前数据块内容read() // -- 递归读取})
    }
    read() // -- 开始读取
    
TransformStreamDefaultController

该 API 用于提供对应操作 ReadableStream 和 WritableStream 的方法 → 该方法同样是没有对应的构造函数的,当在构造 TransformStream 实例对象时,会自动创建对应的 TransformStreamDefaultController 实例对象(传递给对应 TransformStream 的行为方法中)

实例属性:

  • desired: 属性返回填充满流内部队列的可读端所需要的大小

实例方法:

  • enqueue: 该方法用于将给定的分块排入流的可读端 → enqueue(chunk)

  • error: 该方法可以向流的两端(可读流和可写流)抛出错误 → 与它的进一步交互都会失败并携带给定的错误信息,并且队列中的任何分块都将被丢弃 → error(reason)

    • // -- 在这个示例中,当一个分块中包含 symbol 时,error() 方法被使用 → 由开发者控制
      case 'symbol':controller.error("Cannot send a symbol as a chunk part")break
      
  • terminate: 该方法用于关闭两端的流(可读流和可写流) → terminate()

    • 场景: 
      → 正常完成:当转换器处理完所有输入数据,并且没有更多的数据需要发送到下游时
      → 错误处理:如果在转换过程中遇到无法恢复的错误,并且你希望立即停止流的进一步处理
      → 条件终止:基于特定的输入或状态条件,你可能决定提前终止流
      

该 API 具体的用法,在 TransformStream 中进行示例

这篇关于JavaScript 中的 Stream API 04(转换流 TransformStream 等 API)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1123980

相关文章

Java中ArrayList和LinkedList有什么区别举例详解

《Java中ArrayList和LinkedList有什么区别举例详解》:本文主要介绍Java中ArrayList和LinkedList区别的相关资料,包括数据结构特性、核心操作性能、内存与GC影... 目录一、底层数据结构二、核心操作性能对比三、内存与 GC 影响四、扩容机制五、线程安全与并发方案六、工程

JavaScript中的reduce方法执行过程、使用场景及进阶用法

《JavaScript中的reduce方法执行过程、使用场景及进阶用法》:本文主要介绍JavaScript中的reduce方法执行过程、使用场景及进阶用法的相关资料,reduce是JavaScri... 目录1. 什么是reduce2. reduce语法2.1 语法2.2 参数说明3. reduce执行过程

如何使用Java实现请求deepseek

《如何使用Java实现请求deepseek》这篇文章主要为大家详细介绍了如何使用Java实现请求deepseek功能,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录1.deepseek的api创建2.Java实现请求deepseek2.1 pom文件2.2 json转化文件2.2

Java调用DeepSeek API的最佳实践及详细代码示例

《Java调用DeepSeekAPI的最佳实践及详细代码示例》:本文主要介绍如何使用Java调用DeepSeekAPI,包括获取API密钥、添加HTTP客户端依赖、创建HTTP请求、处理响应、... 目录1. 获取API密钥2. 添加HTTP客户端依赖3. 创建HTTP请求4. 处理响应5. 错误处理6.

Spring AI集成DeepSeek的详细步骤

《SpringAI集成DeepSeek的详细步骤》DeepSeek作为一款卓越的国产AI模型,越来越多的公司考虑在自己的应用中集成,对于Java应用来说,我们可以借助SpringAI集成DeepSe... 目录DeepSeek 介绍Spring AI 是什么?1、环境准备2、构建项目2.1、pom依赖2.2

Spring Cloud LoadBalancer 负载均衡详解

《SpringCloudLoadBalancer负载均衡详解》本文介绍了如何在SpringCloud中使用SpringCloudLoadBalancer实现客户端负载均衡,并详细讲解了轮询策略和... 目录1. 在 idea 上运行多个服务2. 问题引入3. 负载均衡4. Spring Cloud Load

Springboot中分析SQL性能的两种方式详解

《Springboot中分析SQL性能的两种方式详解》文章介绍了SQL性能分析的两种方式:MyBatis-Plus性能分析插件和p6spy框架,MyBatis-Plus插件配置简单,适用于开发和测试环... 目录SQL性能分析的两种方式:功能介绍实现方式:实现步骤:SQL性能分析的两种方式:功能介绍记录

在 Spring Boot 中使用 @Autowired和 @Bean注解的示例详解

《在SpringBoot中使用@Autowired和@Bean注解的示例详解》本文通过一个示例演示了如何在SpringBoot中使用@Autowired和@Bean注解进行依赖注入和Bean... 目录在 Spring Boot 中使用 @Autowired 和 @Bean 注解示例背景1. 定义 Stud

如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解

《如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别详解》:本文主要介绍如何通过海康威视设备网络SDK进行Java二次开发摄像头车牌识别的相关资料,描述了如何使用海康威视设备网络SD... 目录前言开发流程问题和解决方案dll库加载不到的问题老旧版本sdk不兼容的问题关键实现流程总结前言作为

SpringBoot中使用 ThreadLocal 进行多线程上下文管理及注意事项小结

《SpringBoot中使用ThreadLocal进行多线程上下文管理及注意事项小结》本文详细介绍了ThreadLocal的原理、使用场景和示例代码,并在SpringBoot中使用ThreadLo... 目录前言技术积累1.什么是 ThreadLocal2. ThreadLocal 的原理2.1 线程隔离2