源码已在文章最后给出
说明书
mockStreamText
这是一个用于在前端模拟文本流式
展示效果的工具函数,能够将完整文本按指定的片段大小和时间间隔逐步展示,适用于模拟 AI 对话回复
、打字机效果
等场景。函数具备完善的参数验证和错误处理机制,确保运行的健壮性。
参数说明
参数名 | 类型 | 必选 | 说明 |
---|---|---|---|
fullText | string | 是 | 需要进行流式展示的完整文本内容 |
options | object | 否 | 配置选项对象,包含以下属性 |
options 配置项
配置项 | 类型 | 默认值 | 说明 |
---|---|---|---|
chunkSize | number | 5 | 每次展示的文本片段大小(正整数) |
interval | number | 50 | 每次展示的时间间隔(毫秒,正整数) |
onChunk | function | () => {} | 每次片段更新时的回调函数,接收当前已展示的文本作为参数 |
onFinal | function | () => {} | 文本全部展示完成时的回调函数,接收完整文本作为参数 |
onError | function | (err) => console.error(...) | 发生错误时的回调函数,接收错误对象作为参数 |
返回值
返回一个取消函数,调用该函数可以终止流式展示过程并释放相关资源。
错误处理
函数会对输入参数进行严格验证,当参数不符合要求时会通过 onError
回调抛出以下错误:
fullText 必须是字符串类型
:当第一个参数不是字符串时chunkSize 必须是正整数
:当 chunkSize 不是正整数时interval 必须是正整数
:当 interval 不是正整数时onChunk, onFinal 和 onError 必须是函数
:当回调函数不是函数类型时
使用示例
以下仅展示核心的JS食用方法
(利用vue的响应式,displayText内容变化,会自动触发页面渲染,实现打字机效果)
javascript
// 引入前端虚拟流式加载工具类
import { mockStreamText } from "@/utils/typeWriter.js"
const backendText = "这是一段需要流式展示的文本内容...";
const displayText = ref("");
const isStreaming = ref(true);
// 启动流式展示
const cancelStream = mockStreamText(backendText, {
chunkSize: 5, // 每次展示5个字符
interval: 50, // 每50毫秒展示一次
onChunk: (text) => { // 片段更新时更新显示
displayText.value = text;
},
onFinal: (fullText) => { // 展示完成时
isStreaming.value = false;
console.log('流式展示结束');
},
onError: (err) => { // 错误处理
isStreaming.value = false;
console.error('发生错误:', err.message);
// 可以在这里添加错误提示UI
}
});
// 如需中途取消展示
// cancelStream();
特殊情况处理
- 当
fullText
为空字符串时,会直接触发onChunk("")
和onFinal("")
,不启动定时器 - 调用返回的取消函数后,会终止定时器并标记为已取消,避免后续回调执行
工作原理
- 进行参数验证,确保输入符合要求
- 初始化状态变量(当前位置、定时器、取消标记等)
- 定义核心处理函数
process
,负责计算片段、触发回调和状态更新 - 立即执行一次
process
并设置定时器循环执行 - 返回取消函数,用于终止流程并释放资源
该工具函数源码
javascript
// 模拟文本流式展示的工具函数(增强健壮性版本)
export function mockStreamText(fullText, options = {}) {
// 1. 参数验证与默认值处理
if (typeof fullText !== "string") {
throw new TypeError("fullText 必须是字符串类型")
}
// 默认配置
const {
chunkSize = 5,
interval = 50,
onChunk = () => {},
onFinal = () => {},
onError = (err) => console.error("流式处理错误:", err),
} = options
// 验证配置参数的有效性
if (!Number.isInteger(chunkSize) || chunkSize <= 0) {
onError(new Error("chunkSize 必须是正整数"))
return () => {} // 返回空的取消函数
}
if (!Number.isInteger(interval) || interval <= 0) {
onError(new Error("interval 必须是正整数"))
return () => {}
}
if (
typeof onChunk !== "function" ||
typeof onFinal !== "function" ||
typeof onError !== "function"
) {
onError(new Error("onChunk, onFinal 和 onError 必须是函数"))
return () => {}
}
// 2. 状态变量初始化
let currentPosition = 0
let timer = null
let isCanceled = false
const textLength = fullText.length
// 3. 核心处理函数(带错误捕获)
const process = () => {
if (isCanceled) return
try {
// 计算下一次要展示到的位置
const nextPosition = Math.min(currentPosition + chunkSize, textLength)
// 获取当前片段并更新位置
const currentChunk = fullText.substring(0, nextPosition)
currentPosition = nextPosition
// 触发片段回调
onChunk(currentChunk)
// 检查是否已经完成所有文本的展示
if (currentPosition >= textLength) {
clearInterval(timer)
timer = null
onFinal(currentChunk) // 触发结束回调
}
} catch (err) {
// 错误处理
clearInterval(timer)
timer = null
onError(err)
}
}
// 4. 启动流式处理(空文本特殊处理)
if (textLength === 0) {
// 空文本直接触发结束回调
onChunk("")
onFinal("")
return () => {}
}
// 立即执行一次,然后设置定时器
process()
timer = setInterval(process, interval)
// 5. 返回取消函数(确保资源正确释放)
return () => {
if (!isCanceled) {
isCanceled = true
if (timer) {
clearInterval(timer)
timer = null
}
}
}
}