响应式图片

响应式是指实现不同屏幕分辨率的终端上浏览网页的不同展示方式。 本知识点的主要内容有: 为什么要使用响应式图片 怎么实现响应式图片 1、为什么要使用响应式图片 假如有一张图片的显示宽度为200px,那么,它在 1x(即设备像素比为 1 的显示器) 的显示器上,是占了 200 个物理像素(即实际所占的像素);它在 2x 的显示器上,实际上是占了 400 个物理像素;在 3x 的显示器上,实际上是占了 600 个物理像素;在 4x 的显示器上就是占了 800 个物理像素。 如果这个图片只提供 200 像素的尺寸,那么在 2x~4x 的显示器上看起来就很模糊。如果只提供 800 像素的版本,那么在 1x~3x 的设备上会显得多余,因为加载时间会相较长,所以我们要使用响应式图片。 再比如一个场景,相同的banner,在电脑上需要使用大图,但是手机上面使用小图,不然会造成手机上加载慢浪费流量等问题,这也可以使用响应式图片来解决。 2、实现方法 css3 media query 一个办法是使用backgound-image结合媒体查询,如下所示: .banner{ background-image: url(/static/large.jpg); } @media screen and (max-width: 767px){ background-image: url(/static/small.jpg); } 这种方法的缺点是对SEO不太友好,因为如果使用img标签还可以写个alt属性。 picture标签 <picture> <source srcset="banner_w1000.jpg" media="(min-width: 801px)"> <source srcset="banner_w800.jpg" media="(max-width: 800px)"> <img src="banner_w800.jpg" alt=""> </picture> 如上,如果页面宽度大于800px(PC),则加载大图,而在手机上加载小图。这样写浏览器就只会加载source里面的一张图片。但是如果是用js动态插进去的,它还是会去加载两张,只有写在html里面加载初始化页面的时候才只加载一张。 picture必须要写img标签,否则无法显示,对picture的操作最后都是在img上面,例如onload事件是在img标签触发的,picture和source是不会进行layout的,它们的宽和高都是0。 另外使用source,还可以对图片格式做一些兼容处理: <picture> <source type="image/webp" srcset="banner.webp"> <img src="banner.jpg" alt=""> </picture> webp在保持同等清晰度的情况下,体积可以减少一半,但是目前只有Chrome支持,Safari和firefox一直处于实验阶段,所以其它的浏览器如firefox将会加载jpg格式的照片: ...

September 27, 2024

表单控件

01、<form>表单 表单是比较重要的HTML元素,主要作用是向服务端提交数据。比如结合表单元素input使用,通过内部的button按钮提交(type=“submit”)表单数据。 元素/属性 描述 值/备注 <form> 表单元素 action 提交表单的目标(服务端)地址url method 提交数据的方式,就是数据传输的方式 get:通过URL提交数据 url?uname=1&age=2;post,通过HTTP表单数据提交,键值格式。 target 提交数据时打开action url的方式 _self:当前窗口(默认值);_blank:新窗口 enctype 编码类型(encode type),规定了form表单在发送到服务器时候编码方式,不常用。 application/x-www-form-urlencoded:编码所有字符(默认);multipart/form-data :混合类型, 表单中有文件上传时使用;text/plain:纯文体,空格转换为 “+” 加号,不对特殊字符编码 submit() 提交表单数据,通过js代码调用 <fieldset> 表单分组,默认样式:一个框 便于表单样式管理的语义化元素 form from的id,当<fieldset>不在form中时 disabled 整个分组都不可用 <legend> 作为<fieldset>的标题,显示在框上 (legend /ˈledʒənd/ 铭文、图例) <style> #form fieldset { border: 1px solid skyblue; padding: 20px 10px; border-radius: 5px; text-align: center; margin: 10px 0px; } #form fieldset legend { font-size: 1em; border: 1px solid rgb(236, 175, 43); border-radius: 1em; padding: 3px 15px; } </style> <form id="form" action="#" target="_self" method="post"> <fieldset> <legend>登录</legend> <input type="text" name="uname" placeholder="请输入用户名" required maxlength="36"> <input type="password" name="upwd" required maxlength="12" placeholder="输入密码"> <input type="submit" value="submit-登录"> </fieldset> </form> 📢注意:<form>提交数据时参数名为表单元素的name,因此表单控件须设置name属性。 ...

September 25, 2024

语义化

HTML 语义化是什么? HTML 语义化是指使用 HTML 标签来正确地表示文档的结构和内容的方式。通过使用正确的标签和元素,可以使网页的结构更加清晰、易于理解,并且对搜索引擎和辅助技术(如屏幕阅读器)更友好。 CSS 命名的语义化指的是在给 CSS 类名、选择器和 ID 命名时,使用具有语义的名称来描述元素的用途和功能。这样的命名方式可以使代码更具可读性、可维护性和可拓展性。 为什么需要语义化? 有利于搜索引擎优化(SEO):搜索引擎依赖于网页的结构和语义来识别和理解网页内容。使用语义化的 HTML 标签可以提高网页在搜索引擎结果的排名,从而提高页面的 SEO(搜索引擎优化)。 可读性和可维护性:使用语义化的代码可以增强代码的可读性和可维护性,有利于开发人员理解和维护代码。同时,遵循 W3C 标准的团队可以遵循相同的标准,减少差异化,提高团队的效率和协调能力。 提高可访问性:语义化可以提高网页的可访问性,让页面更容易被搜索引擎、辅助技术(如屏幕阅读器)解析和理解,让更多的人能访问和理解网页。 可间接提升网页的性能:在传统的 HTML 代码中,有时候会存在一些重复的标签和属性,导致代码冗余。使用语义化的 HTML 代码,可以减少这种冗余,让代码更加简洁和高效。 面向未来的 HTML ,浏览器在未来可能提供更丰富的支持。 一些常用的语义化标签及使用场景 布局相关的语义化标签: <header> 标签:用于定义文档或一个节的头部区域。通常包含网页的标题、导航栏、logo 或其他相关信息;作用是为页面提供附加的信息或功能,以帮助用户更好地理解或导航网页内容。适用于表示网页或一个节的顶部区域。 <aside> 标签:用于定义与页面内容相关但可以被视为独立于主要内容的部分。它通常用于侧边栏、广告、导航链接、附加信息或其他类似的内容。 <section> 标签:用于表页面中的一个独立部分,具有明确的主题或目的。例如文章、评论、产品列表、产品规格及描述等。一个页面可以包含多个不同主题的 section ;并且这个标签可以包含标题、段落、列表、表格等其他HTML元素。 <nav> 标签:用于表示导航菜单,包括主导航、子导航、面包屑导航等。这个标签通常包含链接(<a> 标签)来指向其他页面或网站的部分。 <footer> 标签:用于表示文档的页脚,通常包含版权信息、联系方式、法律声明等内容。它通常出现在页面的底部,并且只应该出现一次。 <main> 标签:用于表示页面中的主要内容区域,是所有主要内容(包括头部、尾部和侧边栏)的容器。每个<main>元素都应该包含独特的内容,这部分内容在页面上是唯一的,且对整个页面来说是重要的。<main>标签不能包含在页面其它区块元素中,通常是<body>的子标签,或者是全局<div>的子标签。 <address> 标签:用于表示联系信息,通常包含地址、电子邮件地址、电话号码等。这个标签通常用于定义页面或其部分内容的作者或拥有者的联系信息。 举个栗子🌰: <body> <!-- 页面的头部 --> <header> <h1>欢迎来到我的网站</h1> <p>这是网站的标题,用于展示网站的核心信息。</p> </header> <!-- 导航菜单 --> <nav> <ul> <li><a href="#">首页</a></li> <li><a href="#">关于我们</a></li> <li><a href="#">产品</a></li> <li><a href="#">联系我们</a></li> </ul> </nav> <!-- 主要内容区域 --> <main> <!-- 第一个内容区块 --> <section></section> <!-- 第二个内容区块 --> <section> <aside></aside> <aside></aside> </section> </main> <!-- 联系信息 --> <address> <p><strong>联系信息:</strong></p> <p>电话:(123) 456-7890</p> <p><a href="mailto:example@email.com">example@email.com</a></p> </address> <!-- 页面的底部 --> <footer> &copy; 2023 My Website. All rights reserved. | 设计:北冥有锅 </footer> </body> 文本相关语义化标签: figure 和 figcaption、del 和 ins <figure> 标签:用于处理带有某些嵌入式内容的一组图,照片,代码清单等。表示独立的内容单元,它可以包含任何与主内容相关的附加内容,包括但不限于:文本内容、媒体文件、交互式内容等。使用<figure>标签时应当注意内容的独立性和相关性,确保它与主内容是相关的,并且不依赖于主内容而存在。 <figcaption> 标签:<figcaption>标签是<figure>元素的一部分,并且它是可选的。它应该包含在<figure>标签内部,作为其第一个或最后一个子元素。一个<figure>标签中只能有一个<figcaption>标签。 <del> & <ins> 标签: <del> 用作已删除内容的标签。浏览器通常通过在已删除的文本上打一行删除线来呈现它。 <ins> 用于表示HTML文档中新添加的文本。它通常在文本上带有下划线。 <ins> 与<del> 一起使用时更有用,他们都可以使用CSS属性进行更改。 <ins> 与<del> 的特定属性: cite:URL => 它指定资源的URL,该URL解释更改或删除文本的原因。 datetime:YYYYMMDD || HH:MM:SS => 它指定更改或删除文本的日期和时间。 举个栗子🌰: ...

September 24, 2024

DOCTYPE

DOCTYPE 是一个声明,位于 HTML 文档的最顶部,指示浏览器使用哪种 HTML 或 XHTML 版本来渲染页面。它的主要作用是确保浏览器以标准模式解析文档,从而避免不同浏览器间的渲染差异。正确使用 DOCTYPE 可以提升页面的兼容性和可访问性。 <!DOCTYPE>声明应该位于HTML文档的第一行,紧接着是<html>标签。 例如,对于 HTML5 文档,你只需写: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Document Title</title> </head> <body> <!-- 页面内容 --> </body> </html> 这个声明告诉浏览器该文档是一个HTML5文档。HTML5是最新的HTML标准,它包括了许多现代化的功能,如语义元素、表单控件、音频和视频等。 DOCTYPE 的作用有以下几个方面: 指定 HTML 版本:浏览器根据 DOCTYPE 的声明来确定使用哪个 HTML 版本来渲染页面,从而保证页面在不同的浏览器上显示一致性。 触发标准模式:在 HTML 中,如果省略了 DOCTYPE 声明,浏览器会进入混杂模式(Quirks mode),这种模式下浏览器的渲染方式与早期的浏览器相同,可能导致页面的显示出现不可预测的错误。而指定了 DOCTYPE 声明,则会触发标准模式(Standards mode),使得浏览器按照 HTML 规范的要求进行页面渲染,从而保证页面的稳定性和可靠性。 供浏览器和开发人员参考:DOCTYPE 声明还包含了有关 HTML 文档的元信息,例如所使用的 DTD(文档类型定义),以及其他的元数据信息,这些信息可以供浏览器和开发人员参考,帮助开发人员更好地了解和掌握 HTML 语言的特点和规范。 提高网页加载速度:指定 DOCTYPE 声明可以帮助浏览器更快地加载网页,因为浏览器知道要使用哪种渲染模式,从而更快地解析 HTML 文档。 避免代码错误:指定 DOCTYPE 声明可以帮助开发人员在编写 HTML 代码时遵循标准,避免一些常见的代码错误,例如忘记关闭标签或者使用非法的属性和元素等等。 除了HTML5的<!DOCTYPE>声明之外,还有一些其他版本的HTML和XHTML文档类型声明。这里是一些例子: 1. HTML 4.01 Strict: ...

September 24, 2024

HTML 5 新特性

HTML5 新特性 语义标签 增强型表单 视频和音频 Canvas绘图 SVG绘图 地理定位 拖拽API WebWorker WebStorage WebSocket 语义标签 语义化标签使得页面的内容结构化,可以使开发者更方便清晰地构建页面的布局 标签 描述 <header> 定义了文档的头部区域 <footer> 定义了文档的尾部区域 <nav> 定义文档的导航 <section> 定义文档中的书 <acticle> 定义页面独立的内容区域 <aside> 定义页面侧边栏内容 <details> 定义用户可以看到或隐藏的额外细节 <summary> 标签包含details元素的标题 <dialog> 定义对话框 <figure> 定义自包含内容,如图表 <main> 定义文档主内容 增强型表单 HTML5新增input输入特性,改善更好的输入控制和验证 输入类型 描述 color 主要用于选取颜色 date 选取日期 datetime 选取日期(UTC时间) datetime-local 选取日期(无时区) month 选择一个月份 week 选择周和年 time 选择一个时间 email 包含email地址的输入域 number 数值的输入域 url url地址的输入域 tel 定义输入电话号码的字段 search 用于搜索域 range 一个范围内数字值的输入域 HTML5也新增了五个表单元素 ...

September 24, 2024

选择题 面试题

共 154 道 选择题 面试题。答案默认折叠,便于先自行作答。 1. 对以下代码说法正确的是? 难度:1 · 类型:Choice let arr = [1,2,3,4,5]; let arr2 = [1, , 3]; A. 执行 arr.length = 3,此时数组为 [1,2,3] B. 执行 arr[10] = 11,此时 arr.length 为 6 C. 执行 delete arr[2],此时 arr.length 为 4,数组为 [1,2,4,5] D. arr2.length 的长度为 2 题目要点 考察的是数组的length属性: 参考答案 正确答案:A 考察的是数组的length属性: 设置数组的length值为小于当前值的非负整数n,则任何索引大于或等于n的数组元素都会从数组中被删除 如果给一个索引为i​的数组元素赋值,而i大于或等于数组当前的length,则数组的length属性会被设 置为i+1​ 对数组元素使用delete操作符不会修改length属性,使用splice()​会 如果省略数组字面量中的一个值,被省略的元素是不存在的,但它的索引是存在的 2. 下列哪些不可以实现浏览器存储数据? 难度:1 · 类型:Choice A. cookie B. localStorage C. session D. sessionStorage 题目要点 session 不是浏览器端 API,指的是服务端会话机制,不能直接用于浏览器存储 参考答案 正确答案:C session 不是浏览器端 API,指的是服务端会话机制,不能直接用于浏览器存储 ...

跨端技术 面试题

共 19 道 跨端技术 面试题。答案默认折叠,便于先自行作答。 1. 跨平台的开发中,如何处理不同平台的 API 差异? 难度:2 · 类型:QA 题目要点 条件编译:在编译阶段,通过特定注释(如 // #ifdef MP-WEIXIN)来区分不同平台,编写差异化代码。 适配器模式(Adapter Pattern):在运行时,封装一个统一的工具类(Adapter),在内部判断环境并调用对应的原生 API。例如,封装一个 StorageAdapter,内部判断环境并分别调用 uni.setStorageSync 或浏览器的 localStorage,对业务代码提供统一的 Promise 接口 。 参考答案 处理不同平台的 API 差异,是跨平台开发中的核心挑战。其目标是在享受跨平台开发效率的同时,确保应用在各平台上的功能完整、性能稳定、体验原生。关键在于通过良好的架构设计来隔离与抽象平台细节。 核心原则与架构思想 抽象与统一接口层:这是最根本的策略。不要在各处业务代码中直接调用平台特定的 API,而是封装一个统一的接口层。业务逻辑只与这个抽象层交互,由它来屏蔽底层的平台差异。例如,一个文件操作模块,可以定义统一的 readFile 和 writeFile 方法,然后在内部根据平台调用不同的原生实现 。这种设计使得核心业务代码保持平台无关性,极大提升了可维护性 。 渐进增强与平稳退化:在设计功能时,采用“渐进增强”思想。即,优先保证核心功能在所有平台都能运行,然后为高版本平台或特定平台增强更优的体验。同时,做好“平稳退化”,对于不支持某些高级功能的平台,提供合适的降级方案,而不是让功能崩溃 。 关键技术方案与手段 条件编译:这是在编译时处理差异的高效方式。通过预定义的宏或配置,编译器只会将当前目标平台的代码打包到最终产物中 。例如,在 C++ 或前端构建工具中,可以使用 #ifdef _WIN32 或类似语法,为不同平台编写不同的代码路径。这种方式打包结果纯净,但需要构建工具支持 。 运行时检测与分支判断:这是在代码运行时根据当前所处的平台环境,动态选择执行不同的逻辑。这是最常见和灵活的方式 。各框架通常提供全局的 API 用于获取平台信息,例如 React Native 的 Platform.OS 和 Platform.select() 方法 ,或 UniApp 中的 uni.getSystemInfoSync().platform 。这种方式灵活直观,但代码中会存在一些分支判断。 文件/模块约定:一些框架支持通过特定的文件命名约定来区分平台代码。例如,在 React Native 中,可以创建 Component.ios.js 和 Component.android.js 文件。在导入时,只需 import Component from './Component',框架会自动根据平台加载正确的文件 。这是一种将平台差异隔离在文件级别的优雅实践。 ...

趣味题 面试题

共 35 道 趣味题 面试题。答案默认折叠,便于先自行作答。 1. 过桥问题 难度:2 · 类型:QA 在一个夜晚,同时有4人需要过一桥,一次最多只能通过两个人,且只有一只手电筒,而且每人的速度不同。A,B,C,D需要时间分别为:1,2,5,10分钟。问:在17分钟内这四个人怎么过桥? 题目要点 第一步:A、B过花时间2分钟。 参考答案 第一步:A、B过花时间2分钟。 第二步:B回花时间2分钟。 第三步:C、D过花时间10分钟。 第四步:A回花时间1分钟。 第五步:A、B再过花时间2分钟。 2. 圆环转圈问题 难度:2 · 类型:QA 两个圆环,半径分别是1和2,小圆在大圆内部绕大圆圆周一周,问小圆自身转了几周?如果在大圆的外部,小圆自身转几周呢? 题目要点 小圆所转动的路程便是小圆圆心走过的距离 参考答案 小圆所转动的路程便是小圆圆心走过的距离 所以在大圆外部转动,小圆圆心饶半径为3的大圆心转动,走了三圈 所以在大圆内部转动,小圆圆心饶半径为1的大圆心转动,走了一圈 3. 推理问题(二) 难度:1 · 类型:QA 赵女士买了一些水果和小食品准备去看望一个朋友,谁知,这些水果和小食品被他的儿子们偷吃了,但她不知道是哪个儿子。为此,赵女士非常生气,就盘问4个儿子谁偷吃了水果和小食品。老大说道:“是老二吃的。”老二说道:“是老四偷吃的。”老三说道:“反正我没有偷吃。”老四说道:“老二在说谎。”这4个儿子中只有一个人说了实话,其他的3个都在撒谎。那么,到底是谁偷吃了这些水果和小食品? 题目要点 是老三偷吃了水果和小食品,只有老四说了实话。 参考答案 是老三偷吃了水果和小食品,只有老四说了实话。 用假设法分别假设老大、老二、老三、老四都说了实话,看是否与题意矛盾,就可以得出答案。 4. 最后剩下谁? 难度:2 · 类型:QA 1~50 号运动员按顺序排成一排。教练下令:“单数运动员出列!”剩下的运动员重新排队编号。教练又下令:“单数运动员出列!”如此下去,最后只剩下一个人,他是几号运动员?如果教练下的令是“双数运动员出列!”最后剩下的又是谁? 题目要点 教练下令“单数”运动员出列时,教练只要下5次命令,就能知道剩下的那个人。 参考答案 教练下令“单数”运动员出列时,教练只要下5次命令,就能知道剩下的那个人。 此人在下第五次令之前排序为2,在下4次令之前排序为4,在下3次令之前排序为8,在下2次令之前排序为16,在下1次令之前排序为32,即32位运动员,因此答案是32号。 如果教练下的令是“双数运动员出列!”,最后剩下的是1号。 5. 推理问题(一) 难度:1.5 · 类型:QA 甲、乙、丙三个人在一起做作业,有一道数学题比较难,当他们三个人都把自己的解法说出来以后: 甲说:“我做错了。” 乙说:“甲做对了。” 丙说:“我做错了。” 在一旁的丁看到他们的答案并听了她们的意见后说:“你们三个人中有一个人做对了,有一个人说对了。” 请问,他们三人中到底谁做对了? 题目要点 假设丙做对了,那么甲、乙都做错了,这样,甲说的是正确的,乙、丙都说错了,符合条件,因此,丙做对了。 参考答案 假设丙做对了,那么甲、乙都做错了,这样,甲说的是正确的,乙、丙都说错了,符合条件,因此,丙做对了。 ...

设计模式 面试题

共 7 道 设计模式 面试题。答案默认折叠,便于先自行作答。 1. 开发的过程中你用到过哪些设计模式? 难度:3 · 类型:QA 题目要点 设计模式是一种被广泛接受并经过验证的面向对象软件开发中的最佳实践。它们提供了一套解决常见问题的可重用设计方案。 参考答案 设计模式是一种被广泛接受并经过验证的面向对象软件开发中的最佳实践。它们提供了一套解决常见问题的可重用设计方案。 以下是一些常用的设计模式: 单例模式(Singleton):确保一个类只有一个实例,并提供全局访问点来获取该实例。 工厂模式(Factory):通过工厂方法创建对象,而不是直接使用new操作符。这样可以隐藏具体实现,并根据需要创建所需类型的对象。 观察者模式(Observer):定义了一种一对多的依赖关系,当一个对象状态发生改变时,它的所有依赖者(观察者)都会收到通知并自动更新。 装饰器模式(Decorator):动态地将责任附加到对象上。通过将对象包装在装饰器对象中,可以在运行时为对象添加新的行为。 策略模式(Strategy):定义了一系列算法,将每个算法封装起来并使它们可以相互替换。策略模式可以让算法独立于客户端而变化。 适配器模式(Adapter):将一个类的接口转换成客户端所期望的另一个接口。适配器模式使得原本由于接口不匹配而无法一起工作的类可以协同工作。 每个设计模式都有其特定的应用场景和优缺点,可以根据具体情况来选择使用。设计模式可以提高代码结构的灵活性、可维护性和可扩展性,并促进重用和解耦。然而,需要根据实际需求慎重选择和应用设计模式,避免过度设计或不必要的复杂性。 2. 什么是 MVVM?比之 MVC 有什么区别?什么又是 MVP ? 难度:3 · 类型:QA 题目要点 MVC(Model-View-Controller):将应用程序分为模型、视图和控制器。控制器处理用户输入并更新模型和视图。 MVVM(Model-View-ViewModel):将应用程序分为模型、视图和视图模型。视图模型处理视图和模型之间的交互,通过数据绑定简化状态管理。 MVP(Model-View-Presenter):将应用程序分为模型、视图和展示者。展示者处理视图和模型之间的交互,并负责更新视图和模型。 每种模式都有其适用场景和优缺点,选择哪一种模式通常取决于应用程序的需求和团队的开发习惯。 参考答案 MVC、MVP 和 MVVM 是三种常见的软件架构设计模式,主要通过分离关注点的方式来组织代码结构,优化我们的开发效率。 比如说我们实验室在以前项目开发的时候,使用单页应用时,往往一个路由页面对应了一个脚本文件,所有的页面逻辑都在一个脚本文件里。页面的渲染、数据的获取,对用户事件的响应所有的应用逻辑都混合在一起,这样在开发简单项目时,可能看不出什么问题,当时一旦项目变得复杂,那么整个文件就会变得冗长,混乱,这样对我们的项目开发和后期的项目维护是非常不利的。 MVC 通过分离 Model、View 和 Controller 的方式来组织代码结构。其中 View 负责页面的显示逻辑,Model 负责存储页面的业务数据,以及对相应数据的操作。并且 View 和 Model 应用了观察者模式,当 Model 层发生改变的时候它会通知有关 View 层更新页面。Controller 层是 View 层和 Model 层的纽带,它主要负责用户与应用的响应操作,当用户与页面产生交互的时候,Co ntroller 中的事件触发器就开始工作了,通过调用 Model 层,来完成对 Model 的修改,然后 Model 层再去通知 View 层更新。 ...

计算机网络 面试题

共 104 道 计算机网络 面试题。答案默认折叠,便于先自行作答。 1. 说说流式输出的原理及其应用场景 难度:3 · 类型:QA 题目要点 流式输出的本质是将结果按时间拆分为连续数据流,实现边生成、边传输、边消费;它通过降低首字节时间和提升反馈及时性来改善用户体验;常见于大模型推理、长耗时任务、实时数据和媒体传输等场景;但同时也带来更高的工程复杂度,需要在体验收益与系统成本之间进行权衡。 参考答案 流式输出并不是一种新的计算模型,而是一种结果传递与消费方式的改变:从“一次性生成、一次性返回”,变为“边生成、边传输、边消费”。理解它的关键,不在于某个具体 API,而在于数据生产方、传输层和消费方三者如何协同工作。 一、流式输出的基本原理 1. 传统非流式模式 在非流式模式下,系统的执行流程是严格串行的: 服务端完整计算结果 将结果一次性写入响应 客户端在接收完全部数据后再进行处理或渲染 这种模式的特点是实现简单,但首字节时间(TTFB)和用户感知延迟较高,尤其当计算过程本身很慢时,用户在很长一段时间内得不到任何反馈。 2. 流式输出模式 流式输出的核心变化在于:结果不再作为一个整体返回,而是被拆分为多个连续的数据块。 典型流程是: 服务端在计算过程中,阶段性地产生部分结果 每当有新数据可用,就立刻写入响应流并 flush 客户端持续读取数据流,并逐步消费、渲染或处理 在传输层,这通常依赖于长连接 + 分块传输,例如 HTTP chunked encoding、Server-Sent Events 或 WebSocket。 3. 从系统视角看流式输出 从系统设计角度,流式输出具备以下特征: 数据是按时间顺序增量产生的 消费方不需要等待生产方完全结束 生产与消费之间形成一种弱同步关系 这使得系统整体从“请求-响应”模型,转变为一种更接近“发布-订阅”的交互方式。 二、前端视角下的实现机制 在前端,流式输出通常体现在如何读取并渲染增量数据。 以 HTTP 流为例: 浏览器通过 Fetch API 获取一个 ReadableStream 通过 getReader() 持续读取字节块 将字节解码为文本或结构化数据 逐步更新 UI,而不是等全部完成 这种方式要求前端具备更细粒度的状态管理能力,例如处理中间态、取消、错误恢复等问题。 三、典型应用场景 1. 大模型推理与对话系统 这是当前最典型的应用场景之一。 模型在生成文本时是逐 token 产生的,流式输出可以让用户几乎立即看到内容开始出现,显著降低等待焦虑,同时也便于中途打断和重试。 ...