简历问答
可展示代码示例(用于面试展示/复盘)
说明:这里收纳“适合贴代码”的部分,避免把逐字稿写成代码仓库。 建议面试现场做法:先讲思路与取舍 → 再打开本文件挑 1-2 段关键代码讲。
1)Webpack:拆包、长缓存、产物分析
1.1 splitChunks / runtimeChunk
// webpack.prod.js(片段示例)
module.exports = {
optimization: {
runtimeChunk: 'single',
splitChunks: {
chunks: 'all',
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
name: 'vendors',
priority: 10
},
common: {
minChunks: 2,
name: 'common',
priority: 0,
reuseExistingChunk: true
}
}
}
}
}1.2 contenthash + 静态资源缓存策略(要点)
- JS/CSS 文件名用
contenthash,避免“小改动导致全量缓存失效”。 - CDN 强缓存 + 可回滚发布策略配套(缓存不是越长越好,关键是可控)。
1.3 sideEffects 的正确打开方式
// package.json(示例)
{
"sideEffects": ["*.css", "*.scss"]
}要点:不要把 sideEffects 一刀切设为 false,否则可能误伤样式导入。
2)性能:RUM(Web-Vitals)上报闭环
// rum.ts(示例)
import { onLCP, onCLS, onINP, onFCP, onTTFB } from 'web-vitals'
function report(metric: { name: string; value: number; id: string }) {
navigator.sendBeacon?.(
'/rum',
JSON.stringify({
name: metric.name,
value: metric.value,
id: metric.id,
url: location.href,
ua: navigator.userAgent,
ts: Date.now()
})
)
}
export function initRum() {
onLCP(report)
onCLS(report)
onINP(report)
onFCP(report)
onTTFB(report)
}讲解要点:
- 口径要说清楚:线上采样、P75/P95、按路由/按地域/按网络类型拆维度。
- 目标不是“跑分”,而是“可定位、可回归、可持续”。
3)资源优先级:preconnect / preload
{/* index.html(示例) */}
<link rel="preconnect" href="https://cdn.example.com" crossorigin />
<link
rel="preload"
href="/assets/critical-font.woff2"
as="font"
type="font/woff2"
crossorigin
/>讲解要点:
preconnect解决的是“连接建立”成本。preload解决的是“关键资源优先级”,只给确定影响首屏的资源。
4)脚本加载:defer / async 的取舍
<script src="/assets/app.js" defer></script>
<script src="https://third-party.example.com/sdk.js" async></script>讲解要点:
defer:不阻塞解析,且按顺序执行(适合业务主包)。async:下载完成就执行,顺序不保证(适合独立第三方脚本)。
5)图片 WebP 兜底:<picture>
<picture>
<source srcset="/img/banner.webp" type="image/webp" />
<img src="/img/banner.jpg" alt="banner" loading="lazy" />
</picture>讲解要点:
- 前端兜底最稳定;特殊 WebView 可加能力探测(缓存结果)。
- 升级必须配监控:图片失败率、LCP 波动、错误日志。
6)ESLint:从 0-1 的落地方式(示例骨架)
// .eslintrc.cjs(示例)
module.exports = {
root: true,
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint', 'import', 'promise', 'react-hooks'],
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'plugin:promise/recommended',
'plugin:import/recommended',
'plugin:import/typescript',
'prettier'
],
rules: {
// 质量类:尽量 error
'@typescript-eslint/no-floating-promises': 'error',
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
// 可读性:可 warn → 渐进收紧
'import/order': ['warn', { 'newlines-between': 'always' }],
// Hooks:必须 error
'react-hooks/rules-of-hooks': 'error',
'react-hooks/exhaustive-deps': 'warn'
}
}讲解要点:
- Prettier 管格式、ESLint 管质量,避免两者打架。
- 策略:新增必过、存量渐进;提交前自动修、CI 卡点。
7)React:错误边界(Error Boundary)
import React from 'react'
export class ErrorBoundary extends React.Component<
{ fallback?: React.ReactNode; children: React.ReactNode },
{ hasError: boolean }
> {
state = { hasError: false }
static getDerivedStateFromError() {
return { hasError: true }
}
componentDidCatch(error: unknown) {
// 上报错误(示例)
// reportError(error)
}
render() {
if (this.state.hasError) return this.props.fallback ?? null
return this.props.children
}
}讲解要点:
- 目的:把“局部崩溃”隔离掉,不影响主流程。
- 配套:错误上报 + 降级 UI + 可回滚。
8)NestJS:Cron 定时 + 幂等(示意)
import { Injectable } from '@nestjs/common'
import { Cron } from '@nestjs/schedule'
@Injectable()
export class ReportJobService {
@Cron('0 */5 * * * *')
async generateReports() {
// 关键点:
// 1) 使用幂等键/分布式锁,避免多实例重复执行
// 2) 任务实例入库,记录状态与产物
// 3) 生成逻辑最好放到 worker/队列
}
}讲解要点:
- cron 只负责触发;执行要有幂等/锁。
- 导出是重活:队列化、并发控制、超时与告警。