一. 讲一下浏览器的 Event Loop 机制,宏任务和微任务的执行顺序是怎样的? setTimeout和 Promise 的执行顺序有什么区别?
-
Event Loop 机制:浏览器执行 JS 的单线程机制,任务分为宏任务(macro task)和微任务(micro task)。
- 执行栈为空时,取一个宏任务执行(比如 script、setTimeout、setInterval、I/O 回调)。
- 宏任务执行过程中产生的微任务会立即执行(Promise.then、MutationObserver)。
- 当前宏任务执行完毕后,执行微任务队列,直到清空。
- 清空微任务后,渲染更新(repaint/reflow),然后取下一个宏任务。
-
执行顺序示例:
console.log('script start');
setTimeout(() => console.log('setTimeout'), 0);
Promise.resolve().then(() => console.log('promise1'))
.then(() => console.log('promise2'));
console.log('script end');
输出顺序:
script start → script end → promise1 → promise2 → setTimeout
- 原因:微任务优先于下一个宏任务执行;setTimeout 是宏任务。
二. CSS 中,position 有哪些值? 它们分别是根据什么定位的?
- static:默认值,不做特殊定位,按照文档流排列。
- relative:相对定位,相对于自身在文档流中的原位置进行偏移。
- absolute:绝对定位,相对于最近的已定位祖先元素(非 static)进行定位,脱离文档流。
- fixed:固定定位,相对于视口定位,脱离文档流,滚动不动。
- sticky:粘性定位,基于滚动位置在 relative 与 fixed 之间切换。
三. Webpack 和 Vite 有什么区别? 为什么 Vite 的开发环境启动速度会快很多?
-
Webpack:打包器(bundler),构建时将所有模块打包成一个或多个 bundle。
- 开发模式:每次变更都需要重新打包整个依赖图,慢。
-
Vite:原生 ES Module + Rollup 打包器,利用浏览器原生模块化。
- 启动快:不打包整个应用,浏览器按需请求模块(按需加载 ES module),只编译实际访问的模块。
- 热更新快:模块级别 HMR,不刷新整个页面。
四. 你对前端工程化的理解,除了构建工具,还包括哪些?
- 构建工具:Webpack、Vite、Rollup
- 包管理:npm、yarn、pnpm
- 模块化开发:ES Modules / CommonJS
- 自动化:脚本化任务、CI/CD
- 代码规范:ESLint、Prettier
- 测试:单元测试、集成测试
- 监控与性能分析:前端监控、RUM、Lighthouse
- 部署和版本管理:CDN、灰度发布、版本控制(git)
五. 我看你简历里这个项目挺复杂的,能具体展开讲一下吗? 你在其中扮演了什么角色,解决了哪些核心的技术难题?
-
项目描述:例如大型电商 SPA,包含商品浏览、购物车、支付、后台管理。
-
个人角色:前端主开发/架构设计。
-
核心技术难题:
- 大型状态管理(Redux/Context/Observable)
- 性能优化(首屏加载、虚拟列表、懒加载)
- 模块拆分与路由懒加载
- 跨域与接口统一封装
- 异常监控(白屏、Promise 错误、接口失败重试)
六. 如果要从零设计大型电商网站的前端架构,你会如何进行技术选型?需要考虑哪些方面?
-
技术选型:React/Vue/TS + Webpack/Vite + Node.js 后端 + GraphQL/REST
-
考虑方面:
- 团队熟悉程度
- 可维护性和可扩展性
- 性能优化空间
- 组件库和开发效率
- SSR/SEO 需求
- 状态管理方案(Redux/MobX/Vuex/Pinia)
- 构建和部署方案(CI/CD、CDN、缓存策略)
七. 微前端了解吗? 讲讲主流实现方式及优缺点,你在项目里用过吗?效果如何?
-
实现方式:
- iframe 沙箱:简单隔离,但性能差、通信复杂
- JS/CSS 沙箱(如 single-spa):多个子应用独立加载,较高灵活性
- Webpack Module Federation:共享依赖,按需加载,体积小
-
项目实践:使用 single-spa,将购物车和商品列表拆分为微应用,实现独立部署与团队协作,用户感知无明显差异。
八. 项目里状态管理如何选型? Redux、MobX 或其他方案,它们的核心设计思想是什么?
- Redux:单一状态树 + 不可变数据 + action + reducer。适合复杂应用,需要严格数据流。
- MobX:响应式编程,状态可变但自动追踪依赖,适合中小型或频繁更新的应用。
- 选型考虑:状态复杂度、团队熟悉程度、调试工具支持、性能要求。
九. 讲一下 React Fiber 架构,它解决了什么问题? 相比 Stack Reconciler 的变化?
-
问题:Stack Reconciler 同步渲染,阻塞主线程,长任务影响用户体验。
-
Fiber 架构:将渲染任务拆成小单元(Fiber 节点),支持可中断渲染、优先级调度和增量更新。
-
变化:
- 支持时间切片(Time Slicing)
- 支持并发模式(Concurrent Mode)
- 更新过程可暂停、恢复和优先级调度
十. 项目中如何处理异常和监控?JS 错误、白屏问题、性能数据如何收集和上报?
-
方法:
- JS 错误:
window.onerror
/window.addEventListener('unhandledrejection')
- 白屏:监听页面 DOMContentLoaded / 首屏渲染情况
- 接口错误:fetch / axios 拦截器
- 性能数据:Performance API / Lighthouse / RUM
- JS 错误:
-
上报方式:日志上报到后台服务或第三方监控平台(Sentry、RUM)
十一. 如果页面加载很慢,你会从哪些方面排查和优化?
- 网络:Bundle 体积、请求数量、CDN、gzip/brotli
- 资源:图片/字体优化,懒加载
- JS 执行:长任务优化,虚拟列表,异步加载
- 渲染:减少重绘重排,CSS 优化
- 缓存:HTTP cache、Service Worker
- 监控:Lighthouse、Chrome DevTools、RUM
十二. 从浏览器输入一个 URL 到页面完整展示,中间发生了什么?
1. 概念
浏览器从输入 URL 到页面渲染完成是一个完整的请求、处理、渲染流程,涉及网络、HTTP 协议、浏览器渲染引擎、JS 执行等多个环节。
2. 原理/流程
-
DNS 解析
- 浏览器检查缓存(DNS cache / OS cache / router cache)
- 未命中则向 DNS 服务器请求解析域名到 IP
-
TCP 连接
- 建立三次握手:SYN → SYN-ACK → ACK
- 确认客户端与服务器可通信
-
TLS 握手(HTTPS)
- 协商加密算法和密钥
- 建立加密通道保证通信安全
-
HTTP 请求
- 浏览器发送 GET/POST 请求
- 带上请求头(Cookie、User-Agent、Referer 等)
-
服务器处理
- 解析请求 → 数据库查询 → 构建响应
- 返回 HTML / CSS / JS / 图片资源
-
浏览器解析 HTML
- 生成 DOM 树
- 遇到外部 CSS/JS,会阻塞渲染或异步加载
-
解析 CSS
- 生成 CSSOM 树
- CSSOM + DOM → Render Tree
-
布局(reflow)
- 计算每个元素的尺寸和位置
-
绘制(paint)
- 根据 render tree 绘制像素
-
JS 执行
- 解析、编译、执行 JS
- 可能操作 DOM / CSSOM → 触发二次 reflow/repaint
-
资源加载
- 图片、字体、异步请求等按需加载
-
完成渲染
- 用户看到完整页面
3. 示例/优化点
- 首屏渲染慢 → 可使用 SSR 或 Code Splitting
- 大 JS 文件 → 异步加载 + Tree-shaking
- 图片 → 懒加载,使用 WebP
十三. HTTP 常见状态码有哪些?301 和 302 的区别?
1. 概念
HTTP 状态码用来表示请求结果。分为五类:1xx、2xx、3xx、4xx、5xx。
2. 详细分类
- 1xx 信息性:100 Continue
- 2xx 成功:200 OK, 201 Created
- 3xx 重定向:301 Moved Permanently, 302 Found, 304 Not Modified
- 4xx 客户端错误:400 Bad Request, 401 Unauthorized, 403 Forbidden, 404 Not Found
- 5xx 服务器错误:500 Internal Server Error, 502 Bad Gateway
3. 301 vs 302
- 301:永久重定向,浏览器会缓存,SEO 会更新索引
- 302:临时重定向,浏览器不更新 SEO 索引
4. 实践/注意事项
- 重定向链过长会影响性能
- 使用 301 替换永久域名或 HTTPS 转换
- 使用 302 临时维护或 A/B 测试
十四. 盒模型理解,标准盒模型和 IE 盒模型区别,如何切换?
1. 概念
- 盒模型:每个元素在页面上占用的空间由
content + padding + border + margin
构成 - 标准盒模型(content-box):width/height 只计算 content
- IE 盒模型(border-box):width/height 包含 content + padding + border
2. 原理
- 浏览器渲染元素时,先计算 content → padding → border → margin
- 标准模型和 IE 模型差异会导致布局计算不一致
3. 示例
/* border-box 模型 */
* {
box-sizing: border-box;
}
- 适合现代布局,因为设置宽度不受 padding/border 影响
4. 注意事项
- Flex/Grid 布局建议使用 border-box
- IE8 以下需兼容写法
十五. 实现三栏布局,两边固定,中间自适应,有几种方法?
1. 概念
三栏布局常用于网站:左右固定宽度导航/广告栏,中间自适应内容区域。
2. 方法/原理
-
Flexbox(一维布局)
- 左右固定宽度,中间 flex:1
- 优势:响应式、简洁
-
CSS Grid(二维布局)
- grid-template-columns 定义列宽
- 优势:复杂布局更直观
-
float + margin(传统方法)
- 左右浮动,中间 margin 自动撑开
- 注意清除浮动
3. 示例
/* Flexbox */
.container { display: flex; }
.left, .right { width: 200px; }
.center { flex: 1; }
/* Grid */
.container { display: grid; grid-template-columns: 200px 1fr 200px; }
4. 注意事项
- Flexbox 默认主轴是 row,可调整为 column
- Grid 可以设置 gap,避免额外 margin/padding
十六. display: none 与 visibility: hidden 的区别
1. 概念
display: none
:元素完全移除,不占空间visibility: hidden
:元素隐藏,但仍占空间
2. 原理
- display 会触发 layout 变化
- visibility 仅影响绘制,不触发布局改变
3. 示例
.hidden1 { display: none; }
.hidden2 { visibility: hidden; }
4. 注意事项
- 动画:visibility 可以与 opacity 配合渐隐显示
- layout 依赖:display:none 会影响后续元素位置
十七. JavaScript 基本数据类型,null 与 undefined 区别
1. 基本类型
Number, String, Boolean, Symbol, BigInt, undefined, null
2. 原理
- JS 变量分为基本类型(值类型)和引用类型(对象、数组、函数)
- 内存分配:基本类型存栈,引用类型存堆,栈存指针
3. null vs undefined
undefined
:声明未赋值的变量null
:程序员手动赋的“空对象”占位
4. 示例
let a; // undefined
let b = null; // null
5. 注意事项
- typeof null → "object"(历史遗留)
- null == undefined → true, null === undefined → false
十八. 原型、原型链,proto 和 prototype
1. 概念
- 每个 JS 对象都有
__proto__
指向其构造函数的 prototype - prototype 是函数对象特有,用于实例继承属性
2. 原理
- 属性查找:先自身属性 → 原型链
- 原型链形成继承机制
3. 示例
function Person(name){ this.name = name; }
Person.prototype.say = function(){ console.log(this.name); }
const p = new Person('Tom');
p.say(); // Tom
console.log(p.__proto__ === Person.prototype); // true
4. 注意事项
- 修改原型会影响所有实例
- proto 可动态修改继承链,但不推荐
十九. 手写深拷贝函数
1. 原理
- 递归复制对象和数组
- 处理循环引用 → 使用 WeakMap 缓存
- 拷贝特殊对象(Date, RegExp, Map, Set 等)
2. 示例
function deepClone(obj, map = new WeakMap()) {
if (obj === null || typeof obj !== 'object') return obj;
if (map.has(obj)) return map.get(obj);
let clone = Array.isArray(obj) ? [] : {};
map.set(obj, clone);
for (let key in obj) {
if (obj.hasOwnProperty(key)) clone[key] = deepClone(obj[key], map);
}
return clone;
}
3. 注意事项
- 函数不拷贝
- 循环引用必须处理
二十. const 与 var 区别,暂时性死区(TDZ)
1. 概念
var
:函数作用域,变量提升,可重复声明let/const
:块作用域,不可重复声明,存在 TDZ
2. TDZ 原理
- 变量在声明之前无法访问,访问会报错
- 编译阶段识别 let/const 未初始化状态
3. 示例
console.log(a); // undefined
var a = 1;
console.log(b); // ReferenceError
let b = 2;
二十一. 最近使用过的前端框架,为什么选择
1. React + TypeScript
- React:组件化、虚拟 DOM、生态丰富
- TypeScript:类型安全、智能提示
2. Vue
- 响应式系统、模板语法、轻量、开发效率高
3. 注意事项
- 项目复杂度、团队熟悉度、生态决定选择
二十二. React 中优化大列表渲染性能
1. 问题
- 数百/千条数据渲染 → 性能低,DOM 节点过多
2. 优化方法
- 虚拟列表(react-window / react-virtualized)
- React.memo / useMemo 避免重复渲染
- 合理 key 避免重新挂载
3. 示例
const Item = React.memo(({data}) => <li>{data}</li>);
二十三. Vue3 与 Vue2 重要改进
- Proxy 响应式,比 defineProperty 完整
- Composition API,逻辑复用更方便
- Fragment、Teleport、Suspense
- 性能优化、Tree-shaking 支持
二十四. 使用 Web Workers 提高性能
- 将耗时 JS 运算放到 Worker 线程
- 主线程保持 UI 流畅
- 示例:
const worker = new Worker('worker.js');
worker.postMessage(data);
worker.onmessage = e => console.log(e.data);
二十五. CSS Grid 和 Flexbox 解决布局问题
- Flexbox:一维布局,适合列表、导航
- Grid:二维布局,复杂网格布局
二十六. JS Event Loop,宏任务与微任务
- 宏任务:script、setTimeout、setInterval
- 微任务:Promise.then、MutationObserver
- 执行顺序:执行栈空 → 微任务队列 → 渲染 → 下一个宏任务
二十七. 模块加载器原理
- 定义模块与依赖
- 静态分析依赖顺序
- 缓存已加载模块
二十八. 静态站点生成器原理及选择
- 构建时生成 HTML → 部署静态资源
- SEO 优化
- 选择:Gatsby/Next.js(React),Hugo/Hexo(内容驱动)
二十九. 前端依赖管理与优化
- npm/yarn/pnpm
- Tree-shaking
- 按需加载
- CDN 或 externals 减少 bundle
三十. SSR 与 CSR 的差异
1. 概念
- CSR(Client Side Rendering) :浏览器下载 HTML + JS,JS 运行后生成 DOM,渲染页面。
- SSR(Server Side Rendering) :服务器直接返回带内容的 HTML,浏览器只需解析即可。
2. 原理
-
CSR:
- 浏览器收到 HTML 骨架(无内容)
- 下载 JS → 执行 → 生成 DOM → 页面可见
-
SSR:
- 服务器运行框架(如 Next.js / Nuxt.js)
- 生成完整 HTML 返回
- 浏览器展示内容 → JS 接管交互(hydrate)
3. 区别
对比项 | CSR | SSR |
---|---|---|
首屏加载 | 慢(依赖 JS 执行) | 快(直接返回 HTML) |
SEO | 差 | 好(爬虫能抓 HTML) |
交互体验 | 后续快 | 可能需要 hydrate 时间 |
适用场景 | 管理后台、工具类应用 | 电商、新闻门户、博客 |
4. 示例
Next.js SSR 页面:
export async function getServerSideProps() {
const res = await fetch('https://api.example.com/posts');
const posts = await res.json();
return { props: { posts } };
}
三十一. XSS 与 CSRF 防护
1. XSS(跨站脚本攻击)
-
原理:恶意脚本注入网页,在用户浏览时执行。
-
类型:
- 存储型(恶意代码存数据库,反射给用户)
- 反射型(拼接 URL 参数直接执行)
- DOM 型(前端代码执行 eval / innerHTML 等)
2. 防护措施
- 输出内容做转义(
<
→<
) - CSP(内容安全策略)限制脚本来源
- 禁用
eval
、innerHTML
3. CSRF(跨站请求伪造)
- 原理:用户已登录,攻击者诱导发起请求,利用 Cookie 自动带上。
4. 防护措施
- CSRF Token(后端生成随机数,前端提交时校验)
- SameSite Cookie 属性(禁止跨站携带)
- Referer / Origin 校验
三十二. WebSockets 实时通信
1. 概念
- HTTP:请求/响应模式,单向
- WebSocket:全双工通信,浏览器和服务器能随时互发消息
2. 原理
- 客户端发起
Upgrade: websocket
请求 - 服务器返回
101 Switching Protocols
- 双方切换到 WebSocket 协议
3. 示例
const ws = new WebSocket("wss://example.com/socket");
ws.onopen = () => ws.send("hello");
ws.onmessage = e => console.log("收到:", e.data);
ws.onclose = () => console.log("连接关闭");
4. 应用场景
- 实时聊天
- 股票/体育比分推送
- 游戏联机
三十三. PWA(渐进式 Web 应用)
1. 核心优势
- 可离线访问(Service Worker 缓存资源)
- 类似原生 App(安装到桌面,启动无地址栏)
- 支持消息推送(Push API)
2. 转化步骤
- 添加
manifest.json
(图标、启动页、主题色等) - 注册 Service Worker(缓存 + 拦截请求)
- 全站 HTTPS
3. 示例
navigator.serviceWorker.register('/sw.js');
三十四. 代码可维护性保证
1. 方法
- 组件化:拆分 UI 模块
- 模块化:逻辑拆分成 utils / services
- 规范化:ESLint + Prettier 强制风格
- 类型安全:TypeScript
- 测试保障:单元测试 + 集成测试
2. 原理
保证项目多人协作时,修改某一部分不会影响整体。
三十五. 单元测试重要性与框架
1. 重要性
- 快速发现 bug
- 防止回归(改代码导致旧功能失效)
- 提升代码可维护性
2. 常用框架
- Jest(最常用,Facebook 出品)
- Vitest(Vite 生态)
- Mocha + Chai(灵活组合)
- React Testing Library(React 组件测试)
3. 示例
test('加法函数', () => {
expect(add(1, 2)).toBe(3);
});
三十六. 快速学习新技术经验
1. 方法论
- 先读官方文档 → 掌握核心概念
- 动手写 demo → 验证理解
- 遇到问题查源码/issue → 深入机制
- 总结输出文章 → 加深记忆
三十七. 页面加载慢优化思路
1. 网络层面
- CDN 加速
- 压缩资源(gzip/br)
- 按需加载、懒加载
2. 浏览器渲染
- 减少重排/重绘
- 使用 requestAnimationFrame
3. 代码层面
- Tree-shaking
- 代码分割(Code Splitting)
4. 监控工具
- Chrome DevTools
- Lighthouse
三十八. Tree Shaking 原理
1. 概念
- 去掉未使用的代码,减小 bundle
2. 原理
- 依赖 ES Module 静态导入
- 构建工具(Webpack, Rollup, Vite)在编译阶段分析引用关系
3. 示例
// util.js
export function used() {}
export function unused() {}
// index.js
import { used } from './util.js';
used();
构建后只保留 used()
。
三十九. 前端安全实践
1. 主要风险
- XSS(跨站脚本)
- CSRF(跨站请求伪造)
- 点击劫持(iframe 嵌套攻击)
- 依赖漏洞
2. 实践
- 输入校验 & 输出转义
- CSP + SameSite Cookie
- iframe
sandbox
属性 - 定期升级依赖(npm audit fix)
四十. 新技术/工具决策过程
1. 考量点
- 成熟度(是否有大公司使用)
- 社区活跃度(更新频率、Issue 响应)
- 团队熟悉度(是否已有经验)
- 长期维护成本
2. 示例
决定是否上 Redux Toolkit → 评估现有项目状态管理复杂度、团队熟悉程度。
四十一. CI/CD 流程
1. CI(持续集成)
- 每次提交 → 自动构建、跑测试、静态检查
- 保证主分支稳定
2. CD(持续交付/部署)
- 通过 CI 构建产物 → 自动发布到服务器 / CDN
3. 工具
- GitHub Actions
- GitLab CI
- Jenkins
四十二. 可访问性(Accessibility)
1. 概念
让残障人士也能使用网页。
2. 实践
- 提供语义化标签(
<button>
而不是<div>
) - 为图片加
alt
- 提供键盘操作支持(tabindex)
- 对比度达标(WCAG 标准)
四十三. TypeScript 优势与应用
1. 优势
- 类型检查,减少 bug
- 更好的 IDE 提示
- 重构安全性高
2. 应用场景
- 中大型项目
- 团队协作
3. 示例
function add(a: number, b: number): number {
return a + b;
}
四十四. 前端状态管理
1. 常见方案
- Redux(单向数据流,可预测)
- MobX(响应式,学习成本低)
- Vuex / Pinia(Vue 专属)
- React Query / SWR(数据请求状态管理)
2. 选型思路
- 项目规模小:useState / useReducer
- 中型:MobX / Pinia
- 大型:Redux Toolkit
四十五. 大规模 CSS 优化
1. 问题
- 样式冲突
- 体积过大
2. 方案
- BEM 命名规范
- CSS Modules / CSS-in-JS
- 预处理器:SCSS/LESS
- PostCSS 自动优化
- 按需加载:移除未用 CSS(PurgeCSS)
四十六. 前端监控工具
1. 错误监控
- Sentry, Bugsnag → 捕获 JS 异常,堆栈上报
2. 性能监控
- Performance API 收集首屏、白屏时间
- Lighthouse
3. 用户行为
- RUM(Real User Monitoring)
- 采集页面点击、路径、停留时间
四十七. 浏览器兼容性处理
1. 方法
- Autoprefixer:自动加浏览器前缀
- Babel:转译 ES6+ 语法
- Polyfill:填充新特性(如 Promise, fetch)
- Graceful degradation(优雅降级)
- Progressive enhancement(渐进增强)