前端使用ReadableStream.getReader来处理流式渲染

文章目录

  • 前言
  • 一、纯css
  • 二、vue-typed-js插件
    • 1.安装
    • 2.注册
    • 3.使用
    • 总结
  • 三、ReadableStream
    • 1.ReadableStream是什么?
    • 2.ReadableStream做什么?
    • 3.ReadableStream怎么用


前言

需求:让接口返回的文章根据请求一段一段的渲染,同时可以点击“停止生成”按钮后停止请求。
经历:使用纯css,vue-typed-js插件,ReadableStream 三种,虽然前两种并非很完美,但这种一步步排错并解决问题的思路在我看来更为重要。如果你急需判断是否有效果,也可以直接看第三步。
接口返回的数据:由于是一段一段渲染,所以是数组套对象,如下,完整的句子是“我曾满怀激情地憧憬过,也曾经历了无数次失望和沮丧,但最终还是来到了这里。”

[
    {
        "header":{
            "code":"200"
        },
        "chunk":"我"
    },
    {
        "header":{
            "code":"200"
        },
        "chunk":"曾满怀激情地"
    },
    {
        "header":{
            "code":"200"
        },
        "chunk":"憧憬过,也"
    },
    {
        "header":{
            "code":"200"
        },
        "chunk":"曾经历了无数次失望"
    },
    {
        "header":{
            "code":"200"
        },
        "chunk":"和沮丧,但最终还是"
    },
    {
        "header":{
            "code":"200"
        },
        "chunk":"来到了这里。"
    }
]

一、纯css

由于内容较多,这里只会说一下思路,具体的内容会提供原文链接进行查看。
将所有的内容用p标签包裹,默认是隐藏的。然后加上动画,第一个0.5s显示,第二个1s显示,第三个1.5s显示…以此类推。
缺点:需要手动给n个p标签加上样式,而且内容要是固定的才可以,若返回的是不同数据就无法使用了。当然了,博客的title也写的很清除了,让文字一行一行出现或者显示。

参考文章:
css动画让文字一行一行出现: https://www.5axxw.com/questions/simple/dkog6u
css动画让文字一行一行逐渐显示: https://www.5axxw.com/questions/simple/aawr87
https://www.5axxw.com/questions/simple/vy1p34: https://www.5axxw.com/questions/simple/vy1p34

二、vue-typed-js插件

官网地址: https://github.com/Orlandster/vue-typed-js

1.安装

npm install --save vue-typed-js

2.注册

import Vue from 'vue'
import VueTypedJs from 'vue-typed-js'
 
Vue.use(VueTypedJs)

3.使用

<vue-typed-js
   :startDelay="1000"
   :cursorChar="'|'"
   :strings="[
     '<span>我</span>',
     '<span>曾满怀激情地</span>',
     '<span>憧憬过,也曾</span>',
     '<span>经历了无数次失望和沮丧,</span>',
     '<span>但最终还是</span>',
     '<span>来到了这里。</span>',
   ]"
   :contentType="'html'"
 >
 </vue-typed-js>

字段详解:
startDelay 输入延迟时间,单位ms
cursorChar设置光标长什么样子
strings 一个数组,里面是要渲染的数据
contentType 输入的是文本还是html

总结

没有什么坑的,直接安装注册使用即可。但这有一个严重问题我解决不了。strings这个渲染的数组,如果你在vue中watch监听这个数据,每次改变的话,你会发现有旧值和新值,但如果是接口返回的数据,就只会返回数组的第一个对象的值,后面的不会返回拼接数据了,也就是strings在vue-typed-js组件中只会触发一次,

三、ReadableStream

ReadableStream MDN 官网介绍: https://developer.mozilla.org/zh-CN/docs/Web/API/ReadableStream

1.ReadableStream是什么?

Stream API 中的 ReadableStream 接口表示可读的字节数据流。Fetch API 通过 Response 的属性 body (en-US) 提供了一个具体的 ReadableStream 对象。

2.ReadableStream做什么?

我的理解:就是把接口的内容返回 base64 的字节,然后通过getReader()创建一个 reader,并将流锁定。只有当前 reader 将流释放后,其他 reader 才能使用。通过 cancel() 方法返回一个 Promise,这个 promise 会在流被取消的时候兑现。cancel 用于在不再需要来自它的任何数据的情况下(即使仍有排队等待的数据块)完全结束一个流。调用 cancel 后该数据丢失,并且流不再可读。

3.ReadableStream怎么用

(1)你可以将以下代码通过设置了跨域的谷歌浏览器的打开

若你没有设置了跨域的谷歌浏览器,请查看我写的博客【谷歌(Chrome)浏览器的设置跨域】来创建一个跨域的浏览器:https://blog.csdn.net/weixin_44784401/article/details/131111077

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <script>
  fetch("https://www.example.org")
  .then((response) => response.body)
  .then((rb) => {
    const reader = rb.getReader();
    return new ReadableStream({
      start(controller) {
        function push() {
          reader.read().then(({ done, value }) => {
            if (done) {
              console.log("done111", done);
              controller.close();
              return;
            }
            controller.enqueue(value);
            console.log("done222", done, value);
            push();
          });
        }
        push();
      },
    });
  })
  
  </script>
</body>
</html>

(2)效果
在这里插入图片描述
由上图可验证: reader.read().then(({ done, value })中的value表示ReadableStream可读的字节数据流。
(3)结合实际情况进行流式渲染数据的伪代码,我的是vue2 项目

// 注意:以下代码是伪代码,需要你结合自身需求去修改
let _this = this; // 存储this
  let data = '';
  fetch("https://www.example.org", {
    method: 'POST',
    body: JSON.stringify(data)
  })
  .then((response) => {
      const reader = response.body.getReader(); // 创建一个读取器并将流锁定于其上。一旦流被锁定,其他读取器将不能读取它,直到它被释放
      const decoder = new TextDecoder(); // TextDecoder 接口表示一个文本解码器,一个解码器只支持一种特定文本编码,例如 UTF-8、ISO-8859-2、KOI8-R、GBK,等等。解码器将字节流作为输入,并提供码位流作为输出。
      console.log('000', response.body, decoder);
      // 按顺序读取每个分块,并传递给 UI,当整个流被读取完毕后,从递归方法中退出,并在 UI 的另一部分输出整个流。
      function read() {
        // read() 返回了一个 promise 
        // done  - 当 stream 传完所有数据时则变成 true
        // value - 数据片段。当 done 为 true 时始终为 undefined
        return reader.read().then(({ done, value }) => {
          if (done) {
            return;
          }
          let chunkData = ""; // 设置一个存储当前数组对象中数据的字符串
          let chunkJson = JSON.parse(decoder.decode(value)); // decoder.decode(编码)返回一个字符串,其中包含使用特定 TextDecoder 对象的方法解码的文本。(就是将原本变成字节流后把它变成文本)
          // 如果code不是200,说明请求失败,后面不执行
          if (chunkJson.header.code != "200") {
            return;
          }
          chunkData = JSON.parse(decoder.decode(value)).chunk;
          _this.render.contentText += chunkData; // 请求成功拼接字符串
          // reader.cancel()是reader停止请求的方法,停止请求后就不请求了(有一个停止生成的按钮,点击后就停止请求)
          // render.loading 是判断是否正在请求的loading,以此来判断是否继续递归请求后面的数据
          return _this.render.loading ? read() : reader.cancel();
        });
      }
      return read();
    })

ReadableStream 参考链接
(1)MDN ReadableStream : https://developer.mozilla.org/zh-CN/docs/Web/API/ReadableStream
(2)MDN ReadableStream getReader() 方法:https://developer.mozilla.org/zh-CN/docs/Web/API/ReadableStream/getReader
(3)MDN ReadableStream cancel() 方法:https://developer.mozilla.org/zh-CN/docs/Web/API/ReadableStream/cancel
(4)MDN TextDecoder: https://developer.mozilla.org/zh-CN/docs/Web/API/TextDecoder

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/69466.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

MySQL8的特性-MySQL8知识详解

MySQL是一个多用户、多线程的SQL数据库服务器。SQL&#xff08;结构化查询语言&#xff09;是世界上最流行和标准化的数据库语言。下面是MySQL的特性。 1、开源性&#xff1a;MySQL是一个开源的关系型数据库管理系统&#xff0c;可以免费使用和修改。 2、可靠性&#xff1a;M…

链表数组OJ题汇总

前言&#xff1a; 在计算机科学中&#xff0c;数组和链表是两种常见的数据结构&#xff0c;用于存储和组织数据。它们分别具有不同的特点和适用场景。 本博客将深入讨论数组和链表在OJ题目中的应用。我们将从基本概念开始&#xff0c;介绍数组和链表的定义和特点&#xff0c;并…

Visual ChatGPT:Microsoft ChatGPT 和 VFM 相结合

推荐&#xff1a;使用 NSDT场景编辑器助你快速搭建可二次编辑的3D应用场景 什么是Visual ChatGPT&#xff1f; Visual ChatGPT 是一个包含 Visual Foundation 模型 &#xff08;VFM&#xff09; 的系统&#xff0c;可帮助 ChatGPT 更好地理解、生成和编辑视觉信息。VFM 能够指…

《漫画算法:小灰的算法之旅》——赠书活动

我想应该有很多人对我今天推荐的书籍不陌生&#xff0c;《漫画算法&#xff1a;小灰的算法之旅》已经是圈内人熟知的“红人”了&#xff0c;但也存在不断有新人入坑&#xff0c;这里就好好介绍一下这本包上“糖衣”的算法“炮弹”吧&#xff0c;整个过程如同本书形象“Q弾可爱&…

【css】textarea-通过resize:none 禁止拖动设置大小

使用 resize 属性可防止调整 textareas 的大小&#xff08;禁用右下角的“抓取器”&#xff09;&#xff1a; 没有设置resize:none 代码&#xff1a; <!DOCTYPE html> <html> <head> <style> textarea {width: 100%;height: 150px;padding: 12px 20p…

Android开源 Skeleton 骨架屏

目录 一、简介 二、效果图 三、引用 Skeleton 添加jitpack 仓库 添加依赖: 四、使用 Skeleton 1、VIew 骨架屏使用 ViewSkeletonScreen 2、列表类View 骨架屏 RecyclerViewSkeletonScreen、GridViewSkeletonScreen、 ListViewSkeletonScreen 一、简介 骨架屏的作用是…

【C++】开源:ceres和g2o非线性优化库配置使用

&#x1f60f;★,:.☆(&#xffe3;▽&#xffe3;)/$:.★ &#x1f60f; 这篇文章主要介绍ceres和g2o非线性优化库配置使用。 无专精则不能成&#xff0c;无涉猎则不能通。——梁启超 欢迎来到我的博客&#xff0c;一起学习&#xff0c;共同进步。 喜欢的朋友可以关注一下&…

极客教程 scrapy和selenium

selenium 极客教程 使用python 调用scrapy的 爬虫Spider并且相互之间可以正常传参实现全局 常规情况创建&#xff0c;使用命令 scrapy genspider baidu "baidu.com"Python中Scrapy框架详解 浏览器调试模式下&#xff08;F12 或 右键检查&#xff09;Command sh…

linux 下 网卡命名改名

Linux 操作系统的网卡设备的传统命名方式是 eth0、eth1、eth2等&#xff0c;而 CentOS7 提供了不同的命名规则&#xff0c;默认是网卡命名会根据网卡的硬件信息&#xff0c;插槽位置等有关&#xff1b;来分配。这样做的优点是命名全自动的、可预知的&#xff0c;缺点是比 eth0、…

【数学】CF1514 C

Problem - 1514C - Codeforces 题意&#xff1a; 思路&#xff1a; Code&#xff1a; #include <bits/stdc.h>using i64 long long;constexpr int N 2e5 10; constexpr int M 2e5 10; constexpr int mod 998244353;void solve() {int n;std::cin >> n;std:…

基于SpringBoot+Vue的地方美食分享网站设计与实现(源码+LW+部署文档等)

博主介绍&#xff1a; 大家好&#xff0c;我是一名在Java圈混迹十余年的程序员&#xff0c;精通Java编程语言&#xff0c;同时也熟练掌握微信小程序、Python和Android等技术&#xff0c;能够为大家提供全方位的技术支持和交流。 我擅长在JavaWeb、SSH、SSM、SpringBoot等框架…

Tailwind CSS:简洁高效的工具,提升前端开发体验

112. Tailwind CSS&#xff1a;简洁高效的工具&#xff0c;提升前端开发体验 1. 什么是Tailwind CSS&#xff1f; Tailwind CSS是由Adam Wathan、Jonathan Reinink、David Hemphill和Steve Schoger等人共同创建的一种现代CSS框架。与传统的CSS框架不同&#xff0c;Tailwind CS…

OpenEuler 上安装redis服务

访问redis的下载地址 Index of /releases/地址&#xff1a;Index of /releases/ 选择对应的版本。我选择5.0的版本。 下载对应的版本redis wget https://download.redis.io/releases/redis-5.0.8.tar.gz 解压 redis tar -zxvf redis-5.0.9.tar.gz 进入redis目录 cd redis-5…

[git] git基础知识

git是一个免费的、开源的分布式版本控制系统&#xff0c;可以快速高效地处理从小型到大型的各种项目 git易于学习&#xff0c;性能极快 什么是版本控制&#xff1f; 版本控制是一种记录文件内容变化&#xff0c;以便将来查阅特定版本修订情况&#xff0c;可以记录文件修改历史…

React 全栈体系(一)

第一章 React入门 一、React简介 1. 是什么&#xff1f; 是一个将数据渲染为HTML视图的开源JavaScript库。 2. 谁开发的&#xff1f; 由Facebook开源 3. 为什么要学&#xff1f; 原生JavaScript操作DOM繁琐&#xff0c;效率低&#xff08;DOM-API 操作 UI&#xff09; 使…

竞赛项目 深度学习图像风格迁移 - opencv python

文章目录 0 前言1 VGG网络2 风格迁移3 内容损失4 风格损失5 主代码实现6 迁移模型实现7 效果展示8 最后 0 前言 &#x1f525; 优质竞赛项目系列&#xff0c;今天要分享的是 &#x1f6a9; 深度学习图像风格迁移 - opencv python 该项目较为新颖&#xff0c;适合作为竞赛课题…

消息中间件 Asio (C++)

折腾了一上午&#xff0c;看到这个结果的时候泪目了兄弟闷&#xff0c;讲真。我的asio客户端成功收到服务端发来的消息了。虽然这确实是极其智障又简单的入门哈哈 下载独立版本 asio网络通信库新建cmake工程&#xff0c;CMakeLists.txt加载asioasio最简单的服务端和客户端代码…

echarts 横向柱状图

<template><div ref"chart" style"height: 100%"></div> </template><script> import * as echarts from "echarts"; var cate ["质量通病1", "质量通病2", "质量通病3", "质…

【C++】static_cast基本用法(详细讲解)

&#x1f449;博__主&#x1f448;&#xff1a;米码收割机 &#x1f449;技__能&#x1f448;&#xff1a;C/Python语言 &#x1f449;公众号&#x1f448;&#xff1a;测试开发自动化【获取源码商业合作】 &#x1f449;荣__誉&#x1f448;&#xff1a;阿里云博客专家博主、5…

Kotlin~Mediator中介者模式

概念 创建一个中介来降低对象之间的耦合度&#xff0c;关系”多对多“变为“一对多”。 角色介绍 Mediator&#xff1a;抽象中介者&#xff0c;接口或者抽象类。ConcreteMediator&#xff1a;中介者具体实现&#xff0c;实现中介者接口&#xff0c;定义一个List管理Colleagu…