# 自检(面试手册)
简历
大厂简历筛选有一套机制,有大厂经历或学历好或经验匹配的会比较容易通过筛选,缺少光环的需要有其他东西来证明,比如优秀的项目经历,参与过好的开源项目等
简历上描述的技术/内容/项目确保自己是真的熟悉/掌握,看看每个技能是不是自己真的掌握了,能说出个 1.2.3;每个项目是否自己能说清楚,一些细节是否了解,有哪些复盘点,是否有改进空间
简历上描述的应该是与目标岗位直接/间接相关的,其他的比较优秀的点可以一笔带过,不需要花大篇幅介绍这些与目标岗位不符的能力
面试官简历评估时也会看跳槽频率,像 1 年 1 跳这种会被评为不稳定,这时除非学历/经历特别出色的,其他基本就不通过了
面试
面试除了技能/项目知识外,状态也很重要;接到面试电话说明简历评估通过了,时间可以你自己定,如果没准备好,可以把时间拉长些,给自己一些准备时间;要求当场面试的可以礼貌拒绝然后定一个合适的时间
对不同工作年限的同学会有不同的要求,校招主要看潜力,所以基础(计算机、网络)和算法会考得比较多;1~3 年除了潜力外还看经验是否与业务匹配,项目经验;3~5 年看是否有独挡一面的能力,需要在技术上有较好的深度,在做事情方面有自己的一套;大于 5 年的除了深度外对广度也有要求,且需要有跨端和架构设计的能力,对于管理岗位也会看带团队的能力
面试时遇到不会的不用慌,每个人的知识面不一样,碰到不会的很正常,但可以积极思考,首先坦诚表示没有了解过相关知识,然后以现有的知识体系思考下这个问题,说明思路,合理猜测结果
有时会有面试官会刻意施加压力,这时不在于问题回答的是否正确,而在于是否能在这些压力下仍然能够理性思考,面对面试官的每个问题,可以尝试想下面试官问这个问题的背后目的是什么
# 面试要点解析
# 前端基础
javascript
- 原型链
- 继承
- 作用域
- 闭包
- 变量提升
- this 的指向
- 立即执行函数
- instanceof 原理
- bind 的实现
- apply 和 call
- 柯里化
- v8 垃圾回收机制
- 浮点数精度
- new 操作符
- 事件循环机制
- promise 原理
- generator 原理
css
- 盒子模型
- CSS 选择器
- BFC
- position
- flex 布局
- css 优先级
- 双飞冀/圣杯布局
- CSS3 新特性
- CSS 样式隔离
- CSS 性能优化
- 层叠上下文
- div 居中
- 浮动
html&浏览器
- 行内元素、块级元素
- 跨标签页通信
- history 和 hash 两种路由
- DOM 树
- 事件模型
- 缓存策略
- 浏览器架构
- 浏览器工作原理
- 内存泄露
性能
- 前端性能优化指标 RAIL
- 前端性能优化手段
- 重排和重绘
- 白屏
- 大量图片加载优化
- 描述下浏览器从输入网址到页面展现的整个过程
- 动画性能
- 渲染合成层
工程化
- 模块化机制
- tree shaking
- uglify 原理
- babel 原理
- webpack 工作流程
- webpack 插件机制
- webpack loader 机制
- 前端微服务
# 框架
React
- 合成事件
- virtual dom
- setState 过程
- fiber
- 高阶组件
- 错误处理
- 性能优化
Redux
- redux 核心原则
- redux 核心逻辑
Vue
- 数据绑定原理
- computed 和 watch
- slot
- next tick 原理
- keep alive
# 算法
算法
- 动态规划:斐波那契数列 ok
- 数组:合并二维有序数组成一维有序数组 ok
- 链表:反转链表
- 链表:链表有环
- 堆栈队列:判断括号字符串是否有效 ok
- 返回数组中第 k 个最大元素 ing
- 找出数组中和为 sum 的 n 个数 ing
- 贪心:具有给定数值的最小字符串 ok
- 二叉树:最大深度
- 二叉树:层次遍历
- 剪枝:判断数独是否有效
- 二分查找:求解平方根
- 字典树:实现一个字典树
- 动态规划:爬楼梯问题 ok
- 动态规划:最短距离
- 数据结构:LRU 缓存
- 翻转二叉树
编程题
- 实现一个 trim 方法
- 实现一个 deepClone 方法
- 实现 add(1)(2)(3)
- 大数相加
- 拍平数组
- 实现防抖函数
- 实现节流函数
- 实现字符串翻转
- 数组去重
- 实现千位分隔符
- 判断是否是回文数
- 实现一个模板引擎
- 判断一个数是否是素数
- 获取 n 以内所有的素数
# 基础
操作系统
- 进程和线程
- 进程通信
- 进程调度策略
- 死锁
- IO 多路复用
网络
- 七层网络模型
- http
- https
- http2.0
- http3.0
- websocket
- tcp
- udp
# 大前端
Node
- 模块机制
- require 原理
- 事件循环
- cluster 原理
- 流机制
- pipe 原理
- 守护进程
- 进程通信
- 异常处理
# 其他
设计架构
- 常用设计模式
- 重构
- MVVM
- MVC
- MVP
开放问题
- 最近看的书
- 平常的学习途径
- 你比较擅长哪一块,不足的地方在哪里
# 模拟题
(一)
- react setState 是同步还是异步
- 什么是高阶组件,请举例说明
- 解释一下原型链
- instanceof 原理
- apply 和 call 的作用及区别
- position 有哪些值,作用分别是什么
- 说下你对 DOM 树的理解
- 重排和重绘是什么,有什么区别
- https 加密过程是怎样的
- 实现 add(1)(2)(3)
(二)
- react 为什么需要合成事件
- 为什么有时 react 两次 setState,只执行一次
- redux 有哪些原则
- es5 实现继承
- 实现一个 promise
- CSS 选择器有哪些
- 说下事件模型
- 如何减少白屏的时间
- 3 次握手过程
- 判断链表是否有环
(三)
- react 合成事件是什么,和原生事件的区别
- react 如何处理异常
- 闭包的作用和原理
- 0.1+0.2 为什么不等于 0.3
- 什么是 BFC,BFC 有什么作用,如何形成 BFC
- 浏览器缓存策略是怎样的
- 你知道的前端性能优化手段有哪些
- 前端模块化机制有哪些
- http2.0 做了哪些改进
- 求解平方根
(四)
- react 为什么需要 fiber
- redux 中间件机制
- bind 的实现
- 说下 generator 原理
- flex 布局有什么好处
- 如何定位内存泄露
- 渲染合成层是什么
- babel 是什么,怎么做到的
- http2.0 有哪些不足,http3.0 是什么
- 实现一个发布订阅模式
(五)
- vue 的数据绑定机制是如何实现的
- vue next tick 实现原理
- 谈谈变量提升
- new 操作符具体做了什么
- 介绍下盒子模型
- 有哪些方式可以使 div 居中
- 有听过前端性能优化指标 RAIL 吗
- 进程和线程的区别
- tcp 滑动窗口是什么
- 实现一个斐波那契数列
(六)
- vue 的 computed 和 watch 的区别
- 说下 vue 的 keep alive
- 什么是立即执行函数
- 谈下事件循环机制
- css 优先级是怎么计算的
- CSS 相关的性能优化
- 谈下 webpack loader 机制
- 进程通信方式有哪些
- 爬楼梯问题
- 实现一个 trim 方法
(七)
- react fiber 有哪些优点,怎样做到的
- 谈谈你对作用域的理解
- 双飞冀/圣杯布局
- 浮动元素会造成什么影响,如何清除浮动
- 网站首页有大量的图片,加载很慢,如何去优化呢?
- 描述下浏览器从输入网址到页面展现的整个过程
- uglify 原理的是什么
- tcp 重试机制
- 层次遍历二叉树
- 实现节流函数
(八)
- react 有哪些性能优化的点
- v8 垃圾回收机制
- CSS 样式隔离手段
- 行内元素、块级元素有哪些,区别是什么
- 聊下你知道的浏览器架构
- 是否有写过 webpack 插件
- websocket 建立过程
- 合并二维有序数组成一维有序数组
- 实现防抖函数
- 最近看了什么书,有什么心得
(九)
- CSS3 有哪些新特性
- 层叠上下文是什么
- history 和 hash 两种路由方式的最大区别是什么?
- 动画性能如何优化
- tree shaking 是什么,有什么作用,原理是什么
- webpack 工作流程是怎样的
- 什么场景下会用策略模式
- 找出数组中和为 sum 的 n 个数
- 判断括号字符串是否有效
- 平常的学习途径
(十)
- node 模块机制是怎样的
- node require 具体实现是什么
- node 事件循环与浏览器的哪些不一样
- cluster 原理是怎样的
- pipe 原理是怎样的
- node 的异常处理方式
- 适配器和外观模式的区别
- 重构的手段有哪些
- 数组去重
- 你比较擅长哪一块,不足的地方在哪里
# 回答
# Node
# 1. 模块机制
核心要点:
- CommonJS 规范:每个文件是一个模块,通过
require
导入,module.exports/exports
导出 - 模块类型:
- 核心模块(内置模块,如
fs
,http
) - 文件模块(用户自定义模块)
- 第三方模块(
node_modules
)
- 核心模块(内置模块,如
- 加载过程:
- 路径解析(优先缓存 → 核心模块 → 路径查找)
- 文件定位(自动补全
.js
,.json
,.node
扩展名) - 编译执行(不同扩展名使用不同编译器)
- 加入缓存(
require.cache
)
示例:
// 查找顺序示例
require('http') → 核心模块
require('./mod') → 当前目录的 mod.js
require('lodash') → node_modules/lodash
# 2. require
原理
执行流程:
- 解析路径为绝对路径
- 检查
require.cache
是否存在缓存 - 创建
Module
实例(包含exports
,id
,loaded
等属性) - 根据文件类型加载:
.js
:包裹成函数(function(exports, require, module, __filename, __dirname) { ... })
.json
:直接解析为JSON.parse
- 执行模块代码,填充
exports
对象 - 返回
module.exports
关键特性:
- 同步加载
- 缓存机制(相同模块只加载一次)
- 循环依赖处理(未完成的
exports
会被提前暴露)
# 3. 事件循环
六个阶段(libuv 实现):
- Timers:执行
setTimeout
/setInterval
回调 - Pending callbacks:执行系统操作回调(如 TCP 错误)
- Idle/Prepare:内部使用
- Poll:
- 检索新的 I/O 事件
- 执行 I/O 相关回调
- 阻塞在此阶段等待新事件(当没有 check 阶段的回调时)
- Check:执行
setImmediate
回调 - Close callbacks:执行关闭事件回调(如
socket.on('close')
)
关键要点:
process.nextTick
在阶段切换前执行(微任务)setImmediate
在 Check 阶段执行- I/O 回调在 Poll 阶段执行
# 4. Cluster 原理
核心机制:
- Master 进程通过
cluster.fork()
创建 Worker 进程 - 共享服务器端口(底层使用
round-robin
负载均衡) - IPC 通信通道(通过
process.send
和message
事件)
代码示例:
const cluster = require('cluster')
if (cluster.isMaster) {
// Fork workers
for (let i = 0; i < numCPUs; i++) {
cluster.fork()
}
} else {
// Worker 代码
http.createServer().listen(3000)
}
优化策略:
- 心跳检测(防止 Worker 僵死)
- 优雅重启(
disconnect
+exit
事件配合)
# 5. 流机制
四种流类型:
类型 | 特性 | 示例 |
---|---|---|
Readable | 数据生产 | 文件读取流 |
Writable | 数据消费 | HTTP 响应 |
Duplex | 双向流 | TCP socket |
Transform | 数据转换 | Gzip 压缩 |
关键概念:
- 背压(Backpressure):通过
highWaterMark
控制缓冲区大小 - 流动模式:
data
事件驱动 - 暂停模式:
read()
方法手动控制
# 6. pipe
原理
核心实现:
readable.pipe(writable) = {
readable.on('data', (chunk) => {
if (!writable.write(chunk)) {
readable.pause();
}
});
writable.on('drain', () => {
readable.resume();
});
}
特性:
- 自动处理背压
- 错误传播(需手动处理)
- 可链式调用(
a.pipe(b).pipe(c)
)
# 7. 守护进程
创建步骤:
- 创建子进程
- 脱离控制终端(
setsid
) - 改变工作目录
- 重定向标准 I/O
- 错误处理与日志记录
代码示例:
const spawn = require('child_process').spawn
const daemon = spawn(process.argv[0], ['app.js'], {
detached: true,
stdio: 'ignore'
})
daemon.unref()
# 8. 进程通信
通信方式:
方式 | 适用场景 |
---|---|
管道(pipe) | 父子进程间简单通信 |
消息队列 | 跨机器通信 |
共享内存 | 大数据量传输 |
Socket | 网络通信 |
Signal | 进程控制 |
Node.js 实现:
child_process
使用 IPC 通道worker.send()
和process.on('message')
- 底层基于 libuv 的跨平台实现(Unix domain socket / Windows named pipe)
# 9. 异常处理
分层处理策略:
- Try/Catch:同步代码
- Promise.catch:异步代码
- EventEmitter 错误事件:
const stream = createReadStream('file') stream.on('error', err => { /* 处理错误 */ })
- 进程级捕获:
process.on('uncaughtException', err => { logger.error(err) process.exit(1) })
最佳实践:
- 避免阻塞在
uncaughtException
- 使用 domain 模块(已废弃,仅旧项目使用)
- 结合 PM2 等进程管理器实现自动重启
# 总结回答示例
"Node.js 的模块机制基于 CommonJS 规范,通过 require
实现依赖加载,其核心原理包括路径解析、缓存和函数包裹。事件循环分为六个阶段,理解 timers、poll 和 check 阶段的执行顺序至关重要。Cluster 模块通过主进程管理多个 Worker 实现了多核利用,底层使用 IPC 通信。流机制通过背压控制优化了大数据处理性能,pipe
方法则封装了流对接的细节。守护进程需要处理进程分离和日志管理,异常处理要分层级覆盖同步/异步场景。这些机制共同支撑了 Node.js 的高性能服务能力。"