首页/文章/javascript

打字机效果是如何实现的

2025-08-05
9704 分钟
...

分析效果

使用 AI 对话的时候,文字是一个字一个字蹦出来的?它不是等所有内容生成完毕后一次性展示,而是以一种流畅、实时的“打字机”效果呈现,这种体验的背后,隐藏着一种高效的Web技术。它就是服务器推送事件(Server-Sent Events,简称 SSE)

什么是 SSE

从根本上说,SSE 是一种允许服务器单向持续地向客户端(浏览器)推送数据的Web技术。

可以把它想象成一个电台广播

  • 服务器是广播电台,持续不断地播出节目。
  • 客户端是收音机,一旦调到正确的频道,就能持续收听,无需反复请求“现在有什么新节目吗?”。

SSE 仍然是 HTTP 协议,它建立一个从服务器到客户端的长连接,服务器可以随时通过这个连接发送数据,而客户端只需被动接收即可。

如何使用

SSE 的实现非常简洁,其核心流程如下:

发起连接:浏览器用 new EventSource('/your-stream-endpoint') 创建一个实例,给服务器发一个 HTTP GET 请求。

保持连接:服务器收到请求后,发送带特殊响应头 Content-Type: text/event-stream 的响应,并保持该连接开启

发送数据:服务器以特定的文本格式(data: ...\n\n)将事件和数据块发送给客户端

实现流式聊天应用

用Bun启动一个本地服务器,实现sse接口

代码如下

import { serve } from "bun";
import PageApp from "./chat.html";
serve({
  port: 3000,
  routes: {
    "/api/chat": {
      async GET(req) {
        const url = new URL(req.url);
        const message = url.searchParams.get('message');
        if (!message) return new Response("消息不能为空", { status: 400 });

        
        const stream = new ReadableStream({
          async start(controller) {
            const response = `man,hahahaha,what can I say,mambaout!`;

            for (const char of response) {
              const data = `data: ${JSON.stringify({ content: char })}\n\n`;
              controller.enqueue(new TextEncoder().encode(data));
              await new Promise((resolve) => setTimeout(resolve, 50));
            }
            controller.close();
          },
        });

        return new Response(stream, {
          headers: {
            "Content-Type": "text/event-stream",
            "Cache-Control": "no-cache",
          },
        });
      },
    },
    "/": PageApp,
  },
  async fetch(req) {
    return new Response("404", { status: 404 });
  },
});

console.log("http://localhost:3000");


前端代码

// 连接 SSE
const eventSource = new EventSource(`/api/chat?message=${encodeURIComponent(message)}`)

eventSource.onmessage = (event) => {
    const data = JSON.parse(event.data)
    botDiv.textContent += data.content
}

eventSource.onerror = () => {
    eventSource.close()
}

实际效果

打开浏览器控制台可以看到消息是一个字符一个字符发送的

 

它的消息通常还有以下字段 核心字段

  • data: 这是消息的数据载荷。例如: data: {"price": 123.45, "time": "14:30:00"}
  • event: 自定义事件的名称。如果没有这个字段,默认就是 message 事件。例如: event: stock_update
  • id: 事件的唯一标识符。
  • retry: 告知浏览器在断线重连前应等待多少毫秒。
  • : (冒号开头的行): 这是注释行,会被客户端忽略。一个常见的用途是作为“心跳包”,防止因网络长时间无活动而被某些防火墙或代理中断连接。

总结

所以,SSE 的原理可以归结为:

  1. 利用 HTTP 的灵活性:通过特定的 Content-Type 改变了 HTTP 请求的“一次性”行为模式,将其转变为持久连接。
  2. 定义简单的文本协议:规定了 data, id, event 等字段和 \n\n 分隔符,使得数据传输既简单又可扩展。
  3. 在浏览器端内置智能:将连接管理、数据解析和自动重连+断点续传等复杂逻辑封装在 EventSource API 中,极大地简化了开发者的工作。

它并非发明了一个全新的网络协议,而是对现有 Web 基础设施的一次巧妙“再利用”,因此具有极好的兼容性和易用性。

如果您觉得这篇文章有帮助,请点个赞吧~

分享文章

相关文章

更多文章 →
javascript2025-09-18
JavaScript 的多线程能力:Worker
如果你写过一些计算量稍大的 JavaScript 代码,比如图像处理、大量数据排序或者复杂的算法,你几乎肯定遇到过浏览器“卡死”的现象。点击页面没反应,动画也停了,就像整个世界都静止了。 这就是主线程被阻塞的典型后果。因为主线程既要负责执行 JavaScript,又要负责渲染页面、响应用户操作,一旦它被繁重的计算任务占满,就无暇顾及其他,用户体验便直线下降。 这个问题的根源,正是“主线程是单线程的”。那么,如何解决呢? 答案很简单:把这...
学习面试
javascript2025-09-10
手把手教你实现一个EventEmitter
你是不是也遇到过这种情况:代码里各种事件监听和触发,回调函数套了一层又一层,最后自己都理不清哪个事件先触发、哪个后触发了? 别担心,今天我就带你从零开始实现一个自己的事件触发器(EventEmitter),让你彻底掌握事件驱动的精髓,代码清晰度直接提升200%! 为什么要懂EventEmitter? 先说说为什么我们要关心这个。Node.js的核心就是事件驱动,比如文件读写、网络请求,都是通过事件来处理的。不会EventEmitter,...
学习面试
javascript2025-08-09
Web Worker 多线程魔法
你是否曾遇到过网页因为复杂计算而卡顿的情况?今天,让我们一起探索Web Worker的神奇世界,看看如何用多线程技术解决性能瓶颈,并实现流畅的图片压缩功能! 为什么需要Web Worker? 想象一下,你在一个繁忙的餐厅里,只有一位服务员(主线程)负责点餐、上菜、结账所有工作。当客人突然暴增时,这位服务员就会手忙脚乱,其他客人只能干等着… 这就是JavaScript的现状—— 单线程 !所有任务都在一个线程中排队执行,一旦遇到复杂计算(...
学习面试
javascript2025-08-07
🌐AST抽象语法树
AST 是前端开发中一个非常重要的概念,它就像是代码的“编译器”,能够帮助我们理解和操作代码。本文将深入探讨 AST 的原理和应用,带你从零开始了解 AST。 一、什么是 AST? AST(抽象语法树)是一种树形结构,用于表示程序代码的语法结构。它将代码分解为一系列的节点,每个节点代表代码中的一个元素,如变量、函数、表达式等。AST 是编译器和解释器的基础,也是代码分析和转换的关键工具。 1\. AST 的结构 AST 的结构通常包括以...
学习面试
javascript2025-08-04
Promise 从原理到实现
前言 是 异步编程的核心概念之一,它为我们提供了一种更优雅的方式来处理异步操作。 本文将全面剖析 的工作原理,并逐步实现一个符合 规范的 。 正文 一、Promise 基础概念 代表一个异步操作的最终完成(或失败)及其结果值。它有 种状态: 1. pending : ,既不是成功,也不是失败状态 2. fulfilled :意味着操作 完成 3. rejected :意味着操作 状态一旦改变就不能再变,只能从 变为 ,或从 变为 。 二...
学习面试
javascript2025-08-03
Web Worker:让前端飞起来的隐形引擎
在现代 Web 开发中,前端性能优化是一个至关重要的课题,尤其是对于计算密集型的应用,如图像处理、视频处理、大规模数据分析等任务。单线程的 JavaScript 引擎常常成为性能瓶颈,导致应用变得迟缓。 Web Worker ,作为一种强大的技术,使得前端能够在后台进行并行计算,从而实现高效的任务处理,不影响主线程的运行和用户的交互体验。 本文将深入探讨 Web Worker 的概念、工作原理、使用方法以及实际应用场景,帮助你更好地理解...
学习面试

评论

请登录后发表评论

去登录
加载评论中...

目录