字节-技术中台-校招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 2 轮 → 本轮要点: 本次面试主要考察校招生的前端基础知识、框架理解(Vue和React)、TypeScript应用、手写代码能力以及解决实际问题的能力。面试官重点关注以下几个方面: 前端框架深度理解与实践:不仅要求掌握Vue和React的基础知识,更强调对框架设计原理(如Vue的响应式、虚拟DOM)的理解,以及在实际项目中的应用能力(如Vuex到Pinia的迁移,以及在React中模拟Vue特性的思路)。 JavaScript 核心与异步编程:对Object.defineProperty的数据劫持原理、Promise的深入理解及其各种组合与错误处理方式(Promise.all、Promise.allSettled),以及async/await与Promise的关系是考察重点。手写算法题(数组扁平化、深拷贝)考验基础编码功底。 TypeScript 实际应用:考察对TypeScript的熟练程度,包括基本类型、高级类型(如索引签名定义动态属性)的运用,以及如何在项目中利用TypeScript提升代码质量。 工程化与性能优化:Monorepo 多包依赖管理及冲突解决是工程实践的体现。图片懒加载的实现方式(尤其是Intersection Observer API的应用)及其阈值优化,体现了对前端性能优化的关注和实践经验。 整体而言,面试不仅考察"是什么",更侧重"为什么"和"如何做",需要候选人能够结合实际项目经验进行深入分析和解答。 本轮共 20 道题。答案默认折叠,便于先自行作答。 1. 你刚才提到了一些项目经历,讲一个你觉的最有成就感的? 题目要点 这道题是典型的主观题,面试官并不期待一个"唯一标准答案"。 主要考察的是答题者的表达能力、系统性思考问题的方式、对项目及技术的理解深度以及从项目中复盘和学习的能力。 答题结构建议:简述项目背景与挑战 → 描述你的解决方案及遇到的困难 → 总结项目成果与个人成长。 参考答案 在过去的项目经历中,让我最有成就感的是负责公司内部一个复杂的用户权限管理系统重构。这个系统当时面临着用户反馈权限配置混乱、性能瓶颈突出、以及新功能迭代困难等问题。 当时的核心挑战在于,我们有上百种细粒度的权限点,并且需要支持多维度、动态的权限组合,这在旧系统中已经形成了一个巨大的权限矩阵,任何改动都牵一发而动全身。我首先主导了权限模型的梳理和抽象,将权限点进行了归类和分级,并引入了基于角色的访问控制(RBAC)模型,同时考虑了自定义策略的扩展性。技术选型上,我们从传统的后端硬编码权限逻辑,逐步迁移到了前后端分离、统一鉴权服务的方式,并通过引入缓存机制优化了权限查询性能。 在实现过程中,最大的难点是如何在不影响现有业务的前提下,平滑地进行新旧权限系统的切换。为此,我设计了一套灰度发布方案,通过用户白名单和功能开关,逐步验证新系统的稳定性和准确性。在这个过程中,我们也遇到了一些意想不到的数据同步和兼容性问题,例如在特定场景下,新旧权限解析不一致导致的用户访问异常。我积极与后端团队、产品经理沟通,快速定位问题,并及时调整了数据同步策略和回滚机制,确保了业务的连续性。 最终,重构后的权限系统不仅将权限配置的效率提升了30%,还将核心鉴权接口的响应时间从原来的数百毫秒优化到了几十毫秒,极大地提升了系统的性能和稳定性。更重要的是,它为后续的新业务快速上线提供了坚实的基础,权限迭代周期缩短了50%以上。通过这个项目,我不仅深化了对权限系统设计的理解,也锻炼了我在复杂项目中进行技术选型、架构设计、风险管理和跨团队协作的能力。这次经历让我深切体会到,解决核心痛点并为业务带来实际价值,才是技术工作的最大成就感。 2. 项目里 Monorepo 管理多包依赖怎么实现的; 题目要点 Monorepo 概念:理解 Monorepo 的基本思想和优势。 多包依赖管理工具:了解 Lerna、Yarn Workspaces 或 pnpm Workspaces 等工具。 实现方式:掌握如何配置和使用这些工具来管理多包依赖,包括安装、发布、运行脚本等。 软链接/硬链接:理解这些工具如何通过符号链接解决依赖共享和版本管理问题。 参考答案 1.1 原理说明 Monorepo 是一种代码仓库管理策略,它将多个项目的代码存储在同一个版本控制仓库中,而不是为每个项目创建独立的仓库。这种方式的出现是为了解决多项目开发中代码共享、依赖管理、版本控制和协作效率等问题。它与传统的 Multirepo(多仓库)模式相对。 其核心原理在于通过特定的工具(如 Lerna、Yarn Workspaces 或 pnpm Workspaces)来管理仓库内的多个子包(package),实现: 统一的依赖管理:所有包的依赖都集中在一个地方(通常是根目录的 package.json 或各自的 package.json 结合工具配置),避免了重复安装和版本不一致的问题。工具会通过软链接或硬链接的方式将依赖安装到各个子包的 node_modules 中,实现依赖的共享和复用。 统一的构建、测试、发布流程:可以配置统一的脚本来执行所有或部分包的构建、测试和发布流程,简化 CI/CD。 代码共享与重用:各个子包可以直接相互引用,无需发布到 npm 等外部仓库,方便代码共享和模块化开发。 1.2 核心用法 + 示例代码 以 Yarn Workspaces 为例,它作为 Yarn 包管理器的内置功能,提供了一种轻量级的 Monorepo 解决方案。 ...

September 2, 2025

字节跳动-商业化-校招 · 第 2 轮 · 二面

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 本轮要点: 本次面试主要考察前端基础(CSS布局、JavaScript原型链)、React框架深入理解(虚拟DOM、性能优化)、设计模式应用以及算法能力。 本轮共 13 道题。答案默认折叠,便于先自行作答。 1. 实现一个三栏布局,左右两侧固定宽度,中间区域自适应 题目要点 面试官出这道题主要想确认哪些知识维度? 考生对CSS布局(如Flexbox, Grid, 浮动, 定位, 表格布局等)的掌握程度。 考生如何处理不同元素之间的空间分配和自适应能力。 该题所考知识点中有哪些高频实际应用点? 页面整体布局,如经典后台管理系统布局(侧边栏固定,内容区自适应)。 组件内部布局,如卡片、列表项中固定图标/按钮,内容区域自适应。 参考答案 1.1 原理说明 三栏布局是一种常见的网页布局方式,其核心在于实现左右两边固定宽度,中间内容区域根据可用空间自适应。这要求布局方案能够灵活处理流体宽度和固定宽度元素的共存,并且能够正确处理元素之间的堆叠和清除浮动等问题。不同的CSS布局技术提供了不同的实现原理和特性,选择合适的方案取决于兼容性要求、布局复杂度和维护成本。 1.2 核心用法 + 示例代码 以下是几种实现三栏布局的常见方法,并说明其原理和适用场景: 1.2.1 Flexbox 布局 原理: Flexbox (弹性盒子) 是一种一维布局模式,它在父容器中管理子项的分布和对齐。通过设置主轴和交叉轴,可以非常灵活地控制子元素的排列。 使用场景: 现代浏览器环境下的首选布局方式,适用于需要灵活对齐、空间分配的场景。 示例代码: <div class="container-flex"> <div class="left">Left</div> <div class="center">Center</div> <div class="right">Right</div> </div> .container-flex { display: flex; /* 开启Flex布局 */ } .left, .right { width: 200px; /* 左右固定宽度 */ flex-shrink: 0; /* 防止收缩 */ } .center { flex-grow: 1; /* 中间区域自适应,占据剩余空间 */ } 优势: 代码简洁,语义化好,对齐和分配空间非常方便。 1.2.2 Grid 布局 ...

September 2, 2025

字节跳动-商业化-校招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 2 轮 → 本轮要点: 本次面试主要考察前端基础知识、React框架原理、算法能力等多个维度的内容。重点关注CSS布局、页面性能优化、React核心概念等方面。 本轮共 18 道题。答案默认折叠,便于先自行作答。 1. 如何实现一个宽高自适应的正方形元素? 题目要点 CSS布局技巧和响应式设计能力 百分比单位在CSS中的特殊性质理解 现代CSS新特性的应用能力 参考答案 1.1 原理说明 实现宽高自适应的正方形元素的核心在于确保元素的高度能够根据其宽度以1:1的比例进行等比缩放。这通常通过利用CSS中某些属性的特殊计算方式来实现,或者通过现代CSS特性直接声明。以下是几种常见方案的核心原理: 使用padding-top/padding-bottom百分比:在CSS盒模型中,padding属性的百分比值是相对于父元素的宽度来计算的,即使是padding-top和padding-bottom也是如此。因此,当我们将一个元素的height设为0,并将padding-top或padding-bottom设为100%时,它的高度实际上会等于其父元素的宽度,从而形成一个完美的正方形(假设其宽度也为100%)。这种方法利用了这一特性来"撑开"元素的高度。 使用aspect-ratio(现代浏览器支持):aspect-ratio是CSS的一个新属性,它允许开发者直接指定一个元素的宽高比,浏览器会根据这个比率自动计算元素的尺寸。例如,aspect-ratio: 1/1会强制元素保持1:1的正方形比例。这是一个更语义化、更现代的解决方案,减少了传统方法的 hackiness。 使用vw单位:vw(viewport width)是一个相对单位,1vw等于视口宽度的1%。通过将元素的width和height都设置为相同的vw值,例如50vw,可以确保它们始终保持相等的尺寸,并随着视口宽度的变化而自适应缩放,从而形成正方形。 这些方案各有优缺点,如兼容性、代码语义性等,选择哪种方案取决于具体的项目需求和目标浏览器环境。 1.2 核心用法 + 示例代码 在实际开发中,这些方案可以根据兼容性需求和代码简洁性进行选择。 方案1:使用padding-top/padding-bottom百分比 这种方法兼容性好,几乎所有浏览器都支持。常用于需要兼容旧版浏览器或在图片、视频容器中保持比例的场景。 .square { width: 100%; /* 宽度可以设置为百分比、固定值或vw等 */ height: 0; padding-top: 100%; /* padding百分比相对于父元素宽度计算,确保高度与宽度相等 */ background: #eee; /* 内部内容可以通过绝对定位放置,以避免被padding挤压 */ position: relative; } .square-content { position: absolute; top: 0; left: 0; width: 100%; height: 100%; display: flex; justify-content: center; align-items: center; color: #333; } HTML结构示例: <div class="square"> <div class="square-content"> 自适应正方形 </div> </div> 方案2:使用aspect-ratio(现代浏览器支持) 这是CSS3新增的属性,语义化最好,代码最简洁。适用于现代浏览器环境,是推荐的首选方案。 ...

September 2, 2025

字节-国际电商-前端面试 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 已是最后一轮 → 本轮要点: 考察面试者的表达能力、总结归纳能力和个人亮点。 本轮共 17 道题。答案默认折叠,便于先自行作答。 1. 自我介绍 题目要点 主观型问题,无唯一标准答案。 面试官主要考察答题者的表达能力、总结归纳能力、沟通技巧以及对自身经历和技术栈的清晰认知。 答题时建议围绕"我是谁"、“我做了什么”、“我做得怎么样"和"我为什么选择贵公司"这几个核心点展开,突出个人亮点与岗位匹配度。 参考答案 各位面试官好,我叫[您的姓名],毕业于[您的学校],专业是[您的专业]。在校期间,我专注于前端开发方向的学习与实践。在技术栈方面,我熟练掌握 HTML、CSS、JavaScript 基础,并深入学习了 Vue.js 框架,对 Vue 生态系统,如 Vuex、Vue Router 也有实际应用经验。在实习期间,我主要负责[您的项目职责,例如:公司官网前端页面的开发与维护,参与了XX功能模块的重构]。具体工作中,我曾独立负责[具体某个功能或模块],通过[具体技术或方法],实现了[具体效果或优化],比如在[某项目中]实现了[某个功能],有效提升了用户体验[或业务效率]。我个人对前端技术充满热情,具备良好的学习能力和解决问题的能力,期待能将我的技能和经验应用到贵公司,与团队一同成长。 2. 在学校期间有没有参与过什么技术社团或项目,对你的前端学习有什么帮助? 题目要点 主观型问题,无唯一标准答案。 面试官主要考察答题者在校期间对技术的热情、主动学习能力、团队协作能力以及将理论知识应用于实践的能力。他们希望了解你如何将课外活动与前端学习结合,并从中获得了哪些成长。 答题时建议突出你在社团/项目中承担的角色、遇到的挑战、如何解决问题、学到的技术知识以及对个人成长的影响。 参考答案 在校期间,我积极参与了学校的[例如:创新创业协会或某个技术兴趣小组]。在这些活动中,我曾参与一个[例如:校园兼职平台]的小型项目开发。当时,我们团队面临的挑战是[例如:如何利用有限的资源快速搭建一个具备基本交互功能的前端原型]。我主动承担了前端页面的开发工作,通过自学 Vue.js 的组件化思想和路由管理,将页面拆分为可复用的组件,并实现了前端路由功能。虽然项目规模不大,但它让我第一次有机会将课堂上学习的 HTML、CSS、JavaScript 知识体系化地应用到实际开发中。通过这次经历,我不仅锻炼了独立解决问题的能力,还体会到了团队协作的重要性,比如在开发中与后端同学进行接口联调、与设计师沟通 UI 实现细节等,这对我后续的实习和前端学习都产生了积极的推动作用。 3. 说说你实习项目中遇到的技术难点,以及你是如何解决的? 题目要点 主观型问题,无唯一标准答案。 面试官主要考察答题者对项目实践的深入理解、问题解决能力、技术深度以及学习和复盘能力。他们希望了解你在面对挑战时,如何分析问题、寻找解决方案并最终达成目标。 答题时建议围绕"遇到什么难点”、“如何分析与定位问题”、“采用了哪些技术方案”、“解决了什么问题"以及"从中获得了哪些经验和教训"等核心点展开,强调思考过程和技术细节。 参考答案 在我的实习项目中,我曾遇到一个比较棘手的性能问题。我们负责的一个电商列表页面,随着商品数量的增多,首次加载时间变得非常慢,用户体验受到严重影响。通过浏览器开发者工具分析,我发现主要瓶颈在于大量图片资源的加载以及首屏渲染时数据量过大导致的卡顿。 为了解决这个问题,我首先考虑了图片懒加载。我引入了一个 Intersection Observer API 的实现,使得图片只有在进入用户视口时才开始加载,这显著减少了初始的 HTTP 请求数量和带宽消耗。其次,针对数据量大的问题,我调研并实现了虚拟列表。核心思路是只渲染当前可见区域的列表项,并动态计算滚动时的偏移量和渲染范围。这避免了一次性渲染数千个 DOM 节点造成的性能压力。具体实现中,我维护了一个可滚动区域,根据滚动位置动态更新展示的数据索引,并结合 requestAnimationFrame 确保滚动动画的流畅性。 经过这些优化措施,页面的首次加载时间从原来的 8 秒降低到了 2 秒以内,列表滚动时的卡顿现象也基本消除。这个过程让我对前端性能优化有了更深层次的理解,特别是如何结合浏览器 API 和数据结构优化来解决实际问题,也锻炼了我分析和解决复杂性能瓶颈的能力。 4. 解释一下 TS 泛型的概念和作用 题目要点 泛型概念:面试官想确认面试者对泛型的基本定义、作用和设计目的的理解。 泛型作用:考察泛型在增强代码灵活性、类型安全和重用性方面的具体应用。 实际应用:理解泛型在实际开发中如何应用于函数、接口、类等场景,以及其在大型项目中的价值。 参考答案 1.1 原理说明 ...

September 2, 2025

百度-小程序-暑期实习 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 已是最后一轮 → 本轮共 21 道题。答案默认折叠,便于先自行作答。 1. 深拷贝浅拷贝有什么区别?怎么实现深拷贝? 题库原题:深拷贝浅拷贝有什么区别?怎么实现深拷贝? 题目要点 JS数据类型分别基本数据类型和引用数据类型,基本数据类型保存的是值,引用类型保存的是引用地址(this指针)。 浅拷贝共用一个引用地址,深拷贝会创建新的内存地址。 浅拷贝方法 直接对象复制 Object.assign 深拷贝 JSON.stringify转为字符串再JSON.parse 深度递归遍历 参考答案 一、数据类型存储 前面文章我们讲到,JavaScript中存在两大数据类型: 基本类型 引用类型 基本类型数据保存在在栈内存中 引用类型数据保存在堆内存中,引用数据类型的变量是一个指向堆内存中实际对象的引用,存在栈中 二、浅拷贝 浅拷贝,指的是创建新的数据,这个数据有着原始数据属性值的一份精确拷贝 如果属性是基本类型,拷贝的就是基本类型的值。如果属性是引用类型,拷贝的就是内存地址 即浅拷贝是拷贝一层,深层次的引用类型则共享内存地址 下面简单实现一个浅拷贝 function shallowClone(obj) { const newObj = {}; for(let prop in obj) { if(obj.hasOwnProperty(prop)){ newObj[prop] = obj[prop]; } } return newObj; } 在JavaScript中,存在浅拷贝的现象有: Object.assign Array.prototype.slice(), Array.prototype.concat() 使用拓展运算符实现的复制 Object.assign var obj = { age: 18, nature: ['smart', 'good'], names: { name1: 'fx', name2: 'xka' }, love: function () { console.log('fx is a great girl') } } var newObj = Object.assign({}, obj); slice() const fxArr = ["One", "Two", "Three"] const fxArrs = fxArr.slice(0) fxArrs[1] = "love"; console.log(fxArr) // ["One", "Two", "Three"] console.log(fxArrs) // ["One", "love", "Three"] concat() const fxArr = ["One", "Two", "Three"] const fxArrs = fxArr.concat() fxArrs[1] = "love"; console.log(fxArr) // ["One", "Two", "Three"] console.log(fxArrs) // ["One", "love", "Three"] 拓展运算符 const fxArr = ["One", "Two", "Three"] const fxArrs = [...fxArr] fxArrs[1] = "love"; console.log(fxArr) // ["One", "Two", "Three"] console.log(fxArrs) // ["One", "love", "Three"] 三、深拷贝 深拷贝开辟一个新的栈,两个对象的属性完全相同,但是对应两个不同的地址,修改一个对象的属性,不会改变另一个对象的属性 ...

August 21, 2025

百度-用户增长-秋招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 已是最后一轮 → 本轮共 20 道题。答案默认折叠,便于先自行作答。 1. 有没有使用 Node.js 进行开发的经历? 题目要点 “不仅仅用过 Node.js,而且能说清楚在前端团队里它解决了哪些实际问题,产生了什么价值。” 这样比单纯回答“用过/没用过”更有亮点。 参考答案 考察的核心是:对 Node.js 的理解深度和在前端/全栈中的实际应用场景。 回答时可以从以下几个角度展开: 1. 使用场景 前端工程化工具链: 使用 Node.js 驱动构建工具(Webpack、Vite、Rollup 等),编写脚本实现自动化构建、代码检查、Mock Server 搭建。 服务端接口开发: 基于 Express、Koa、NestJS 搭建轻量级 API 服务,用于前后端分离项目的接口模拟或小型后台系统。 中间层 / BFF(Backend for Frontend): 在复杂业务中,用 Node.js 实现前后端解耦,比如统一处理接口聚合、鉴权、缓存。 SSR / SSG 场景: 使用 Next.js 或 Nuxt.js,借助 Node.js 渲染首屏,提升 SEO 和加载体验。 运维与脚本: 编写部署脚本、自动生成文件、批量处理数据。 2. 具体任务 可以结合自身经历强调: 是否搭建过 Mock 服务,辅助前后端并行开发; 是否写过中间层解决跨域、接口聚合问题; 是否在工程化中写过 Node.js 工具脚本(如自动生成路由表、埋点收集脚本); 是否参与过服务端渲染或静态站点生成相关开发。 3. 收获和亮点 对 事件驱动、非阻塞 I/O 有更深理解,能写出高并发场景下的稳定服务; 学会了在前端视角下如何更好地和后端衔接; 在实际项目中通过 Node.js 提升了团队的开发效率(例如通过脚本工具减少重复劳动)。 2. CSS 3D 变形有哪些常见的属性和方法? 题目要点 CSS 3D 变形(3D Transform)是 CSS3 提供的一组属性,用来在三维空间中对元素进行旋转、缩放、平移、倾斜等操作。 ...

August 21, 2025

百度-APP产品研发-秋招 · 第 1 轮 · 二面

← 第 1 轮 · 返回本次面经 · 已是最后一轮 → 面试时间: 60分钟 本轮共 21 道题。答案默认折叠,便于先自行作答。 1. 讲一下你在官网开发中的主要职责,开发的模块以及你觉的比较亮点的地方 题目要点 如果是面试官问到“官网开发中的主要职责、开发的模块以及比较亮点的地方”,一般可以从以下几个角度来回答,既展示你的全局把控能力,又体现你在某些点上有深度。 参考答案 如果是面试官问到“官网开发中的主要职责、开发的模块以及比较亮点的地方”,一般可以从以下几个角度来回答,既展示你的全局把控能力,又体现你在某些点上有深度。 下面是一个参考思路: 1. 主要职责 官网整体架构搭建:根据业务和设计稿,使用 React/Vue + Vite/Next.js/Nuxt.js 等技术栈完成整体框架搭建,包括路由、状态管理、多语言支持等。 公共模块封装:抽象公共组件(如导航栏、页脚、轮播、富文本渲染、内容卡片等),提高复用率,减少重复开发。 性能优化:处理首屏加载速度、资源拆分、图片懒加载、SSR/SSG、SEO 优化。 协作沟通:与产品、UI、后端保持沟通,保证页面上线节奏和质量。 2. 负责的模块(可根据实际情况举例) 首页:承担品牌形象展示,涉及 banner 动效、动态数据展示、视频播放等。 产品/解决方案页:结合后端接口,展示不同产品模块,支持筛选、搜索、动态路由。 活动/新闻动态页:接入 CMS(如 Strapi、Sanity、WordPress 等),支持运营人员通过后台直接发布。 多语言切换模块:基于 i18n 实现官网多语言,支持自动识别浏览器语言,静态资源跟随切换。 SEO 优化模块:处理 meta 信息、OG 标签、站点地图、robots.txt,提升搜索引擎收录效果。 3. 亮点/难点突破 性能优化亮点 利用 SSR/SSG(Next.js/Nuxt.js)提升首屏渲染速度,Lighthouse 分数提升到 90+。 使用图片 CDN + WebP 格式,首页加载时间缩短 30%。 按需加载组件、拆分 bundle,减少首次请求体积。 可配置化思路 引入 CMS 系统,实现官网内容可配置,避免频繁改代码上线,运营可直接维护。 封装通用“模块化组件”,如 Banner、富文本、图文组合,做到拖拽/配置式渲染。 前端体验优化 首页/产品页引入 动效(基于 Lottie 或 GSAP),提升视觉冲击力。 交互细节(滚动吸附、视差动画、过渡效果)增强用户沉浸感。 工程化实践 ...

August 20, 2025

百度-APP产品研发-秋招 · 第 1 轮 · 一面

← 已是第一轮 · 返回本次面经 · 第 1 轮 → 本轮共 15 道题。答案默认折叠,便于先自行作答。 1. 前端实现动画有哪些方式? 题库原题:前端实现动画有哪些方式? 题目要点 前端开发中,实现动画的方法多种多样,每种方法都有其适用场景和优缺点。以下是一些常见的实现方式: CSS 动画: 使用 @keyframes 和 animation 属性定义动画。 优点:易于实现,性能好,易于维护。 缺点:功能相对简单,难以实现复杂的交互动画。 CSS 过渡(Transitions): 使用 transition 属性在状态变化时实现平滑过渡。 优点:简单易用,性能优秀。 缺点:只能用于状态变化的过渡,不适合复杂动画。 JavaScript 动画: 使用 JavaScript 直接操作 DOM 元素的样式属性实现动画。 优点:灵活性高,可以控制动画的每一个细节。 缺点:可能影响性能,需要更多的代码实现。 Web Animations API: 使用 Element.animate() 方法实现动画。 优点:提供更丰富的动画控制和更一致的跨浏览器支持。 缺点:兼容性不如 CSS 动画。 SVG 动画: 使用 SVG 元素和 SMIL(Synchronized Multimedia Integration Language)或 CSS 动画实现动画。 优点:适合矢量图形动画,易于集成。 缺点:浏览器支持和性能可能不如 CSS 动画。 Canvas: 使用 HTML <canvas> 元素和 JavaScript 绘制动画。 优点:适合复杂的图形和游戏动画。 缺点:实现复杂,需要手动管理每一帧的绘制。 CSS 3D 变换: ...

August 19, 2025

状态管理工程化

状态管理是一个前端界老生常谈的话题了,所有前端框架的发展历程中都离不开状态管理的迭代与更替,对于react来说呢,整个状态管理的发展也随着react架构的变更和新特性的加入而不停的做调整,作为一个一起伴随react成长了快5年的开发者,经历过reflux、redux、mobx,以及其他redux衍生方案dva、mirror、rematch等等后,我觉得它们都不是我想要的状态管理的终极形态,所以为了打造一个和react结合得最优雅、使用起来最简单、运行起来最高效的状态管理方案,踏上了追梦旅途。 为何需要状态管理 为何需要在前端引用里引入状态管理,基本上大家都达成了共识,在此我总结为3点: 随着应用的规模越来越大,功能越来越复杂,组件的抽象粒度会越来越细,在视图中组合起来后层级也会越来越深,能够方便的跨组件共享状态成为迫切的需求。 状态也需要按模块切分,状态的变更逻辑背后其实就是我们的业务逻辑,将其抽离出来能够彻底解耦ui和业务,有利于逻辑复用,以及持续的维护和迭代。 状态如果能够被集中的管理起来,并合理的派发有利于组件按需更新,缩小渲染范围,从而提高渲染性能 已有状态管理方案现状 redux 遵循react不可变思路的状态管理方案,无论从git的star排名还是社区的繁荣度,首推的一定是redux这个react界状态管理一哥,约束使用唯一路径reducer纯函数去修改store的数据,从而达到整个应用的状态流转清晰、可追溯。 image.png mbox 遵循响应式的后期之秀mbox,提出了computed、reaction的概念,其官方的口号就是任何可以从应用程序状态派生的内容都应该派生出来,通过将原始的普通json对象转变为可观察对象,我们可以直接修改状态,mbox会自动驱动ui渲染更新,因其响应式的理念和vue很相近,在react里搭配mobx-react使用后,很多人戏称mobx是一个将react变成了类vue开发体验的状态管理方案。 image.png 当然因为mbox操作数据很方便,不满足大型应用里对状态流转路径清晰可追溯的诉求,为了约束用户的更新行为,配套出了一个mobx-state-tree,总而言之,mobx成为了响应式的代表。 其他 剩下的状态管理方案,主要有3类。 一类是不满足redux代码冗余啰嗦,接口不够友好等缺点,进而在redux之上做2次封装,典型的代表国外的有如rematch,国内有如dva、mirror等,我将它们称为redux衍生的家族作品,或者是解读了redux源码,整合自己的思路重新设计一个库,如final-state、retalk、hydux等,我将它们称为类redux作品。 一类是走响应式道路的方案,和mobx一样,劫持普通状态对象转变为可观察对象,如dob,我将它们称为类mobx作品。 剩下的就是利用react context api或者最新的hook特性,主打轻量,上手简单,概念少的方案,如unstated-next,reactn、smox、react-model等。 我心中的理想方案 上述相关的各种方案,都各自在一定程度上能满足我们的需求,但是对于追求完美的水瓶座程序猿,我觉得它们终究都不是我理想的方案,它们或小而美、或大而全,但还是不够强,不够友好,所以决定开始自研状态管理方案。 我知道小和 美、全、强本身是相冲突的,我能接受一定量的大,gzip后10kb到20kb都是我接受的范围,在此基础上,去逐步地实现美、全、强,以便达到以下目的,从而体现出和现有状态管理框架的差异性、优越性。 让新手使用的时候,无需了解新的特性api,无感知状态管理的存在,使其遁于无形之中,仅按照react的思路组织代码,就能享受到状态管理带来的福利。 让老手可以结合对状态管理的已有认知来使用新提供的特性api,还原各种社区公认的最佳实践,同时还能向上继续探索和提炼,挖掘状态管理带来的更多收益。 在react有了hook特性之后,让class组件和function组件都能够享有一致的思路、一致的api接入状态管理,不产生割裂感。 在保持以上3点的基础上,让用户能够使用更精简且更符合思维直觉的组织方式书写代码,同时还能够获得巨大的性能提升收益。 为了达成以上目标,立项concent,将其定义为一个可预测、零入侵、渐进式、高性能的增强型状态管理方案,期待能把他打磨成为一个真真实实让用户用起来感觉到美丽、全面、强大的框架。 说人话就是:理解起来够简单、代码写起来够优雅、工程架构起来够健壮、性能用起来够卓越…… ^_^ concent.png 可预测 react是一个基于pull based来做变化侦测的ui框架,对于用户来说,需要显式的调用setState来让react感知到状态变化,所以concent遵循react经典的不可变原则来体现可预测,不使用劫持对象将转变为可观察对象的方式来感知状态变化(要不然又成为了一个类mobx……), 也不使用时全局pub&sub的模式来驱动相关视图更新,同时还要配置各种reselect、redux-saga等中间件来解决计算缓存、异步action等等问题(如果这样,岂不是又迈向了一个redux全家桶轮子的不归路….. ) 吐槽一下:redux粗放的订阅粒度在组件越来越多,状态越来越复杂的时候,经常因为组件订阅了不需要的数据而造成冗余更新,而且各种手写mapXXXToYYY很烦啊有木有啊有木有,伤不起啊伤不起…… 零入侵 上面提到了期望新手仅按照react的思路组织代码,就能够享受到状态管理带来的福利,所以必然只能在setState之上做文章,其实我们可以把setState当做一个下达渲染指令重要入口(除此之外,还有forceUpdate)。 setState,下达更新指令 仔细看看上图,有没有发现有什么描述不太准确的地方,我们看看官方的setState函数签名描述: 代码语言:txt AI代码解释 setState<K extends keyof S>( state: ((prevState: Readonly<S>, props: Readonly<P>) => (Pick<S, K> | S | null)) | (Pick<S, K> | S | null), callback?: () => void ): void; 通过签名描述,我们可以看出传递给setState的是一个部分状态(片段状态),实际上我们在调用setState也是经常这么做的,修改了谁就传递对应的stateKey和值。 ...

August 7, 2025

单页面架构

传统的多页面应用构建方式: 纯服务端渲染,前后端不分离,使用jsp,jade,’ejs’,’tempalte’等技术在后台先拼接成对应的HTML结构,然后转换成字符串,在每个对应的路由返回对应的数据(文件)即可 Jade模版服务端渲染,代码实现: const express= require('express') const app =express() const jade = require('jade') const result = *** const url path = *** const html = jade.renderFile(url, { data: result, urlPath })//传入数据给模板引擎 app.get('/',(req,res)=>{ res.send(html)//直接吐渲染好的`html`文件拼接成字符串返回给客户端 }) //RestFul接口 app.listen(3000,err=>{ //do something }) 使用jQuery等传统库绘制的前端页面 传统前后端不分离,服务端渲染的优缺点: 优点: SEO友好,因为返回给前端的是渲染好的HTML结构,里面的内容都可以被爬虫抓取到。 对于一些应用性能等要求不高的项目,比如某个公司的静态网页,内容很少的情况下,直接一把梭就好,不用再搭建工程化的环境等 对于后端程序员(全干工程师)来说,不用去特意学习前端框架,公司也不用特意去招聘前端 兼容性好,传统服务端渲染多页面应用吐出来的都是字符串,HTML结构 缺点: 如果项目很大,不利于维护,据我所知,目前很多云计算公司,还有不少都是使用非单页面应用,例如一个几十万行的项目是用jQuery写的,如果注释和文档不是非常齐全,那么真的会无从下手 性能和用户体验,不能跟单页面应用相比 后期迭代,升级空间不大,目前大部分写得比较好的库,都建立vue,react等框架基础上,他们都有一套自己的运行机制,有自己的生命周期,并且不像传统的应用,还加上了一层虚拟DOM以及diff算法 现在类似Ant-Design-pro这样的开箱即用的库已经很多,单页面应用的学习和开发成本已经很低很低,如果还在使用传统的技术去开发新的应用,对于开发人员多内心来说也是一种折磨。 这里并不是说多页面应用不好,只能说各有各自的好,单页面应用如果通过大量的极致优化手段,是可以从不少方面跟原生一拼。 目前的单页面应用: 只有一张Web页面的应用,是一种从Web服务器加载的富客户端,单页面跳转仅刷新局部资源 ,公共资源(js、css等)仅需加载一次,常用于PC端官网、购物等网站 其实只有一个空的DIV标签,其他都是js动态生态的内容 单页面应用实现步骤: 代码实现: 首先是一个静态模板文件 index.html <!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> <div id="root"></div> </body> <script> </script> </html> 在vue react框架的入口文件中指定对应的渲染元素: import React from 'react; import ReactDOM from 'react-dom'; ReactDOM.render( <App/>, document.querySelector("#root") ) 引入react-router或者 react-router-dom,dva等路由跳转的库 配置路由跳转 <HashRouter>//这里使用HashRouter <ErrorBoundary>//React错误边界 <Switch> <Route path="/login" component={Login} /> <Route path="/home" component={Home} /> <Route path="/" component={NotFound} />//404路由或者重定向都可以 </Switch> </ErrorBoundary> </HashRouter> 单页面应用所谓路由跳转,其实最终结果就是: 浏览器的url地址发生变化,但是其实并没有发送请求,也没有刷新整个页面 根据我们配置的路由信息,每次点击切换路由,会切换到不同的组件显示,类似于选项卡功能的实现,但是同时url地址栏会变化 分为HashRouter和BrowserRouter两种模式 自己实现一个粗略的路由跳转: 自己实现传统的Hash模式跳转: hash 就是指 url 后的 # 号以及后面的字符。例如www.baidu.com/#segmentfault,那么#segmentfault就是hash值 ...

August 7, 2025