前端资料
涵盖 React、Next.js、Vue3、Nuxt、Node.js、NestJS 等资料
📑 目录
React 资料
🔥 核心基础
1. React 是什么?它的核心特点是什么?
答案要点:
- 用于构建用户界面的 JavaScript 库
- 核心特点:
- 组件化开发
- 虚拟 DOM(Virtual DOM)
- 单向数据流
- JSX 语法
- 声明式编程
2. 什么是 JSX?浏览器能直接识别吗?
答案要点:
- JSX 是 JavaScript 的语法扩展,允许在 JS 中编写类似 HTML 的结构
- 浏览器不能直接识别,需要通过 Babel 等工具编译为
React.createElement()调用
// JSX
const element = <h1 className="title">Hello</h1>;
// 编译后
const element = React.createElement('h1', { className: 'title' }, 'Hello');
3. 类组件 vs 函数组件的区别?
| 特性 | 类组件 | 函数组件 |
|---|---|---|
| 写法 | ES6 Class | 普通函数 |
| 状态管理 | this.state | useState Hook |
| 生命周期 | 完整生命周期 | useEffect 等 Hooks |
| this 绑定 | 需要处理 this | 无 this 问题 |
| 代码量 | 相对较多 | 简洁 |
4. 什么是虚拟 DOM?工作原理?
答案要点:
- 虚拟 DOM: 用 JavaScript 对象模拟真实 DOM 结构的树形对象
- 工作原理:
- 创建虚拟 DOM 树
- 状态变化时生成新的虚拟 DOM
- Diff 算法比较新旧虚拟 DOM
- 计算出最小变更集(patch)
- 批量更新真实 DOM
5. Diff 算法的核心策略?
答案要点:
- 同层比较: 只比较同一层级的节点,不跨层级比较
- Key 的作用: 通过 key 标识节点,提高 Diff 效率
- 三种操作: 插入、删除、更新
⚡ Hooks 相关
6. 常用的 React Hooks 有哪些?
// useState - 状态管理
const [count, setCount] = useState(0);
// useEffect - 副作用处理
useEffect(() => {
// 组件挂载/更新时执行
return () => {
// 清理函数(组件卸载时执行)
};
}, [dependencies]);
// useContext - 上下文
const value = useContext(MyContext);
// useRef - 引用
const inputRef = useRef(null);
// useMemo - 缓存计算结果
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
// useCallback - 缓存函数
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
7. useEffect 的依赖数组有什么作用?
答案要点:
[](空数组):只在组件挂载和卸载时执行[a, b]:在挂载和依赖项变化时执行- 不写依赖数组:每次渲染都执行
8. useMemo 和 useCallback 的区别?
答案要点:
- useMemo: 缓存函数的返回值,用于优化计算密集型操作
- useCallback: 缓存函数本身,用于优化子组件渲染(配合 React.memo)
9. useLayoutEffect 和 useEffect 的区别?
答案要点:
- useEffect: 异步执行,不阻塞浏览器绘制
- useLayoutEffect: 同步执行,在浏览器绘制前执行,可能阻塞渲染
- 使用场景: useLayoutEffect 用于需要同步执行且影响布局的操作
10. 自定义 Hook 是什么?如何编写?
答案要点:
- 自定义 Hook 是提取组件逻辑到可复用函数的方式
- 命名必须以
use开头
function useWindowSize() {
const [size, setSize] = useState({ width: 0, height: 0 });
useEffect(() => {
const handleResize = () => {
setSize({ width: window.innerWidth, height: window.innerHeight });
};
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return size;
}
🔄 状态管理
11. React 有哪些状态管理方式?
| 方式 | 适用场景 | 特点 |
|---|---|---|
| useState/useReducer | 组件级状态 | 简单,React 内置 |
| Context API | 跨组件共享 | 避免 prop drilling,适合低频更新 |
| Redux | 大型应用 | 可预测的状态容器,单向数据流 |
| Zustand | 中小型应用 | 轻量,简洁 |
| Jotai/Recoil | 原子化状态 | 细粒度更新 |
| React Query | 服务端状态 | 数据获取、缓存、同步 |
12. Redux 的核心概念?
答案要点:
- Store: 存储整个应用的状态
- Action: 描述发生了什么的普通对象
- Reducer: 纯函数,根据 Action 更新状态
- 数据流:
Action → Reducer → Store → View
// Action
const increment = () => ({ type: 'INCREMENT' });
// Reducer
const counterReducer = (state = 0, action) => {
switch (action.type) {
case 'INCREMENT': return state + 1;
default: return state;
}
};
13. Redux Toolkit (RTK) 的优势?
答案要点:
- 简化 Redux 样板代码
- 内置 Immer 支持可变语法
- 内置 Redux Thunk 处理异步
- 更好的 TypeScript 支持
🚀 性能优化
14. React 性能优化的方法?
// 1. React.memo - 阻止不必要的重渲染
const MyComponent = React.memo(({ data }) => {
return <div>{data}</div>;
});
// 2. useMemo - 缓存计算结果
const expensiveValue = useMemo(() => {
return data.filter(item => item.active);
}, [data]);
// 3. useCallback - 缓存回调函数
const handleClick = useCallback(() => {
onAction(id);
}, [id, onAction]);
// 4. 代码分割 - 懒加载
const LazyComponent = lazy(() => import('./Component'));
// 5. Virtual List - 长列表优化
import { FixedSizeList } from 'react-window';
15. 如何避免不必要的渲染?
答案要点:
- 使用
React.memo包裹纯展示组件 - 使用
useMemo缓存复杂计算 - 使用
useCallback缓存函数引用 - 合理使用
key属性 - 避免在 render 中创建新对象/函数
🧪 进阶问题
16. React 18 有哪些新特性?
答案要点:
- 并发渲染(Concurrent Rendering): 可中断的渲染
- 自动批处理(Automatic Batching): 自动合并状态更新
- Suspense 改进: 更好的数据获取支持
- 新的 Hooks:
useId,useTransition,useDeferredValue - Strict Mode 改进: 双重渲染检测副作用
17. 什么是 React Server Components (RSC)?
答案要点:
- 在服务器端执行的 React 组件
- 可以直接访问数据库/文件系统等服务端资源
- 不打包到客户端,减小 bundle 体积
- Next.js App Router 已全面支持
18. React 的合成事件(SyntheticEvent)是什么?
答案要点:
- React 封装了浏览器原生事件的跨浏览器包装器
- 事件委托到 document 或 root 节点
- 事件对象会被复用(pooling),异步访问需要调用
e.persist()
19. 错误边界(Error Boundary)是什么?
答案要点:
- 捕获子组件树 JavaScript 错误
- 防止整个应用崩溃
- 使用
static getDerivedStateFromError和componentDidCatch - 只能捕获类组件错误,不能捕获 Hook 和异步代码错误
20. React Fiber 架构是什么?
答案要点:
- React 16 引入的新协调引擎
- 将渲染工作拆分成小单元,可中断和恢复
- 支持优先级调度,实现并发渲染
- 为 Suspense、并发特性奠定基础
Next.js 资料
🏗️ 基础概念
21. Next.js 是什么?与 React 的区别?
答案要点:
- Next.js: 基于 React 的全栈框架,提供服务端渲染能力
- 核心区别:
特性 React Next.js 渲染方式 仅 CSR SSR、SSG、ISR、CSR 路由 需 react-router 文件系统路由 构建优化 需手动配置 开箱即用 API 路由 无 内置 图片优化 无 next/image
22. Next.js 的渲染模式有哪些?
| 模式 | 缩写 | 说明 | 适用场景 |
|---|---|---|---|
| 服务端渲染 | SSR | 每次请求服务端渲染 | 动态数据、SEO 要求高 |
| 静态生成 | SSG | 构建时预渲染 | 内容不常变的页面 |
| 增量静态再生 | ISR | 构建后动态更新静态页 | 大型静态站点 |
| 客户端渲染 | CSR | 传统 SPA 方式 | 纯交互页面、后台系统 |
// SSR
export async function getServerSideProps() {
const data = await fetchData();
return { props: { data } };
}
// SSG
export async function getStaticProps() {
const data = await fetchData();
return { props: { data } };
}
// ISR
export async function getStaticProps() {
return {
props: { data },
revalidate: 60 // 60秒后重新生成
};
}
23. App Router vs Pages Router 的区别?
答案要点:
- Pages Router: 传统路由,基于
pages/目录 - App Router: Next.js 13+ 新路由,基于
app/目录
| 特性 | Pages Router | App Router |
|---|---|---|
| 目录 | pages/ | app/ |
| 布局 | _app.js、_document.js | layout.js |
| 加载状态 | 需手动实现 | loading.js |
| 错误处理 | 需手动实现 | error.js |
| 服务端组件 | 不支持 | 默认支持 |
| 数据获取 | getServerSideProps 等 | fetch API |
24. Next.js 的路由系统如何工作?
答案要点:
pages/ app/
├── index.js → / ├── page.js → /
├── about.js → /about ├── about/
├── blog/ │ └── page.js → /about
│ ├── index.js → /blog ├── blog/
│ └── [slug].js→ /blog/:slug │ ├── page.js → /blog
└── api/ │ └── [slug]/ → /blog/:slug
└── hello.js → /api/hello │ └── page.js
25. next/image 的优势?
答案要点:
- 自动优化图片格式和大小
- 懒加载(Lazy Loading)
- 防止布局偏移(CLS)
- 响应式图片支持
- 使用现代格式(WebP、AVIF)
⚙️ 进阶特性
26. Middleware 是什么?使用场景?
答案要点:
- 在请求到达页面之前执行的代码
- 使用场景:认证、重定向、A/B 测试、地理位置拦截
// middleware.js
import { NextResponse } from 'next/server';
export function middleware(request) {
const token = request.cookies.get('token');
if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
return NextResponse.redirect(new URL('/login', request.url));
}
return NextResponse.next();
}
export const config = {
matcher: ['/dashboard/:path*']
};
27. API Routes 如何使用?
答案要点:
// pages/api/users.js
export default function handler(req, res) {
if (req.method === 'GET') {
res.status(200).json({ users: [] });
} else if (req.method === 'POST') {
// 创建用户
res.status(201).json({ id: 1, ...req.body });
}
}
// app/api/users/route.js (App Router)
export async function GET() {
const users = await db.getUsers();
return Response.json({ users });
}
export async function POST(request) {
const body = await request.json();
const user = await db.createUser(body);
return Response.json(user, { status: 201 });
}
28. 什么是 ISR(增量静态再生)?
答案要点:
- 构建时生成静态页面
- 运行时按指定间隔重新生成
- 首次访问旧页面,后台生成新页面
- 兼顾性能和实时性
export async function getStaticProps() {
const data = await fetch('https://api.example.com/data');
return {
props: { data },
revalidate: 60, // 60秒后重新验证
};
}
29. Next.js 如何处理 SEO?
答案要点:
- 使用
next/head管理页面元数据 - SSG/SSR 提供完整的 HTML 利于爬虫
- 自动生成 sitemap.xml
- 支持结构化数据
import Head from 'next/head';
export default function Page() {
return (
<>
<Head>
<title>页面标题</title>
<meta name="description" content="页面描述" />
<meta property="og:title" content="Open Graph 标题" />
</Head>
{/* 页面内容 */}
</>
);
}
30. Server Actions 是什么?
答案要点:
- Next.js 14+ 特性
- 在服务端执行的异步函数
- 可直接在组件中调用,无需 API 路由
- 自动处理 CSRF 保护
// app/actions.js
'use server';
export async function createUser(formData) {
const name = formData.get('name');
await db.createUser({ name });
revalidatePath('/users');
}
// app/page.js
import { createUser } from './actions';
export default function Page() {
return (
<form action={createUser}>
<input name="name" />
<button type="submit">创建</button>
</form>
);
}
Vue3 资料
🎯 基础核心
31. Vue3 相比 Vue2 的主要改进?
| 特性 | Vue2 | Vue3 |
|---|---|---|
| 响应式原理 | Object.defineProperty | Proxy |
| 组合式 API | 不支持 | 支持 (Composition API) |
| 性能 | 良好 | 提升 1.3~2 倍 |
| TypeScript | 支持不佳 | 原生支持 |
| 树摇优化 | 有限 | 更好的 Tree-shaking |
| 多根节点 | 不支持 | 支持 (Fragments) |
| Teleport | 不支持 | 内置支持 |
| Suspense | 不支持 | 内置支持 |
32. Options API vs Composition API
Options API:
export default {
data() {
return { count: 0 };
},
methods: {
increment() {
this.count++;
}
},
computed: {
double() {
return this.count * 2;
}
}
};
Composition API:
import { ref, computed } from 'vue';
export default {
setup() {
const count = ref(0);
const double = computed(() => count.value * 2);
const increment = () => count.value++;
return { count, double, increment };
}
};
// 或 <script setup> 语法糖
<script setup>
const count = ref(0);
const double = computed(() => count.value * 2);
const increment = () => count.value++;
</script>
对比:
| 方面 | Options API | Composition API |
|---|---|---|
| 代码组织 | 按选项类型 | 按功能逻辑 |
| 复用逻辑 | Mixins(有缺点) | Composables |
| TypeScript | 类型推断困难 | 完美支持 |
| 学习曲线 | 较平缓 | 需理解更多概念 |
33. Vue3 响应式原理(Proxy vs defineProperty)
答案要点:
Vue2 - Object.defineProperty:
- 只能劫持已存在的属性
- 无法检测数组索引变化和对象新增属性
- 需要递归遍历对象属性
Vue3 - Proxy:
- 可以劫持整个对象
- 支持数组索引和对象新增属性
- 懒代理,性能更好
- 13 种拦截操作
// Vue3 响应式实现简化版
function reactive(target) {
return new Proxy(target, {
get(target, key, receiver) {
track(target, key); // 依赖收集
return Reflect.get(target, key, receiver);
},
set(target, key, value, receiver) {
const result = Reflect.set(target, key, value, receiver);
trigger(target, key); // 触发更新
return result;
}
});
}
34. ref vs reactive 的区别?
| 特性 | ref | reactive |
|---|---|---|
| 数据类型 | 任何类型 | 仅对象/数组 |
| 访问方式 | .value | 直接访问属性 |
| 替换对象 | 可以整体替换 | 会丢失响应性 |
| 适用场景 | 基础类型、需要替换的对象 | 复杂对象、表单数据 |
// ref
const count = ref(0);
console.log(count.value); // 0
count.value++;
// reactive
const state = reactive({ count: 0 });
console.log(state.count); // 0
state.count++;
// 注意:解构会失去响应性
const { count } = state; // ❌ count 不是响应式的
const count = toRef(state, 'count'); // ✅ 正确做法
35. Vue3 的生命周期钩子?
// Options API → Composition API 对照
beforeCreate → setup() 开始
created → setup() 中
beforeMount → onBeforeMount
mounted → onMounted
beforeUpdate → onBeforeUpdate
updated → onUpdated
beforeUnmount → onBeforeUnmount (Vue2: beforeDestroy)
unmounted → onUnmounted (Vue2: destroyed)
errorCaptured → onErrorCaptured
// 新增
onRenderTracked // 调试:依赖被追踪
onRenderTriggered // 调试:组件重新渲染
🔧 进阶特性
36. computed 和 watch 的区别?
| 特性 | computed | watch |
|---|---|---|
| 用途 | 派生状态,缓存结果 | 监听变化,执行副作用 |
| 返回值 | 有 | 无 |
| 缓存 | 有(依赖不变不重新计算) | 无 |
| 适用 | 模板中使用的计算值 | 数据变化时执行异步/复杂操作 |
// computed
const fullName = computed(() => `${firstName.value} ${lastName.value}`);
// watch - 监听单个
watch(count, (newVal, oldVal) => {
console.log(`count changed: ${oldVal} → ${newVal}`);
});
// watch - 监听多个
watch([count, name], ([newCount, newName]) => {
// ...
});
// watchEffect - 自动追踪依赖
watchEffect(() => {
console.log(count.value); // 自动追踪 count
});
37. 什么是 provide/inject?
答案要点:
- 跨层级传递数据,避免 prop drilling
- 祖先组件 provide,后代组件 inject
// 祖先组件
import { provide, ref } from 'vue';
const user = ref({ name: 'John' });
provide('user', user);
// 后代组件
import { inject } from 'vue';
const user = inject('user');
const user = inject('user', defaultValue); // 带默认值
38. Vue3 的 Teleport 是什么?
答案要点:
- 将组件模板渲染到 DOM 其他位置
- 常用于 Modal、Toast、Dialog 等
<template>
<button @click="show = true">打开模态框</button>
<Teleport to="body">
<div v-if="show" class="modal">
<p>模态框内容</p>
<button @click="show = false">关闭</button>
</div>
</Teleport>
</template>
39. Suspense 的作用?
答案要点:
- 处理异步依赖的组件
- 在异步组件加载时显示 fallback 内容
<template>
<Suspense>
<template #default>
<AsyncComponent />
</template>
<template #fallback>
<div>加载中...</div>
</template>
</Suspense>
</template>
40. 自定义指令如何实现?
// 全局注册
app.directive('focus', {
mounted(el) {
el.focus();
}
});
// 局部注册
const vFocus = {
mounted(el) {
el.focus();
}
};
// 使用
<input v-focus />
// 简写形式(只在 mounted 和 updated 时触发)
app.directive('color', (el, binding) => {
el.style.color = binding.value;
});
🏭 工程化
41. Vue3 的状态管理方案?
Pinia(推荐):
// stores/counter.js
import { defineStore } from 'pinia';
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
getters: {
double: (state) => state.count * 2
},
actions: {
increment() {
this.count++;
}
}
});
// Composition API 风格
export const useCounterStore = defineStore('counter', () => {
const count = ref(0);
const double = computed(() => count.value * 2);
const increment = () => count.value++;
return { count, double, increment };
});
Pinia vs Vuex:
| 特性 | Vuex | Pinia |
|---|---|---|
| 语法 | 选项式 | 选项式 + Composition |
| TypeScript | 需额外配置 | 原生支持 |
| 模块化 | namespaced | 自动模块化 |
| 体积 | 较大 | 更轻量 |
| DevTools | 支持 | 更好的支持 |
42. Vue Router 4 的变化?
答案要点:
- 全面支持 Composition API
- 新的导航守卫 API
- 改进的路由匹配
// 组合式函数
import { useRoute, useRouter } from 'vue-router';
const route = useRoute();
const router = useRouter();
console.log(route.params.id);
const goToUser = () => {
router.push({ name: 'user', params: { id: 1 } });
};
// 导航守卫(组件内)
import { onBeforeRouteLeave, onBeforeRouteUpdate } from 'vue-router';
onBeforeRouteLeave((to, from) => {
const answer = confirm('确定离开吗?');
if (!answer) return false;
});
43. 如何优化 Vue3 应用性能?
答案要点:
- 使用
v-once渲染一次不更新的内容 - 使用
v-memo缓存条件渲染 - 使用
shallowRef/shallowReactive减少深层响应式开销 - 异步组件 + Suspense
- 虚拟列表处理大数据
- 合理使用
computed缓存计算
Nuxt 资料
🚀 基础概念
44. Nuxt 是什么?核心特性?
答案要点:
- 基于 Vue 的全栈框架
- 核心特性:
- 服务端渲染(SSR/SSG/ISR)
- 文件系统自动路由
- 自动导入(Auto-imports)
- 模块生态
- SEO 优化
45. Nuxt 3 的渲染模式?
// nuxt.config.ts
export default defineNuxtConfig({
// SSR 模式(默认)
ssr: true,
// 静态生成
nitro: {
prerender: {
routes: ['/about', '/contact']
}
},
// 混合模式
routeRules: {
'/admin/**': { ssr: false }, // 纯客户端
'/blog/**': { isr: 60 } // ISR
}
});
46. Nuxt 的目录结构约定?
.nuxt/ # 构建输出(自动生成)
assets/ # 未编译资源(CSS、字体、图片)
components/ # Vue 组件(自动导入)
composables/ # 组合式函数(自动导入)
layouts/ # 布局组件
middleware/ # 中间件
pages/ # 页面路由(文件系统路由)
plugins/ # 插件
public/ # 静态文件
server/ # 服务端代码(API 路由、中间件)
stores/ # Pinia 状态(可选)
nuxt.config.ts # 配置文件
47. 什么是 Auto-imports?
答案要点:
- 自动导入组件、组合式函数、Vue API
- 无需手动 import
<template>
<!-- 组件自动导入 -->
<MyComponent />
</template>
<script setup>
// Vue API 自动导入
const count = ref(0);
const double = computed(() => count.value * 2);
// 组合式函数自动导入(来自 composables/ 目录)
const user = useUser();
// Nuxt 内置组合式函数
const route = useRoute();
const router = useRouter();
const { data } = await useFetch('/api/data');
</script>
48. Nuxt 的数据获取方法?
<script setup>
// useFetch - 最常用
const { data, pending, error, refresh } = await useFetch('/api/users');
// useAsyncData - 更灵活的控制
const { data: posts } = await useAsyncData('posts', () => {
return $fetch('/api/posts');
});
// 客户端获取
const fetchData = async () => {
const data = await $fetch('/api/data');
};
// 带参数和选项
const { data } = await useFetch('/api/users', {
query: { page: 1, limit: 10 },
server: false, // 只在客户端执行
default: () => [], // 默认值
transform: (data) => data.map(transformUser)
});
</script>
🔧 进阶特性
49. Nuxt 服务端和客户端代码如何区分?
<script setup>
// 只在服务端执行
if (process.server) {
console.log('Server only');
}
// 只在客户端执行
if (process.client) {
console.log('Client only');
}
// 使用组合式函数
onMounted(() => {
// 只在客户端执行
});
// 插件中
export default defineNuxtPlugin({
name: 'my-plugin',
enforce: 'pre', // 执行顺序
async setup(nuxtApp) {
// 插件逻辑
}
});
</script>
50. Server API Routes 如何使用?
// server/api/users.get.ts
export default defineEventHandler(async (event) => {
const query = getQuery(event);
const users = await db.getUsers(query);
return users;
});
// server/api/users.post.ts
export default defineEventHandler(async (event) => {
const body = await readBody(event);
const user = await db.createUser(body);
return user;
});
// server/routes/hello.ts(直接作为路由)
export default defineEventHandler(() => {
return { message: 'Hello!' };
});
// server/middleware/auth.ts(中间件)
export default defineEventHandler((event) => {
const token = getHeader(event, 'authorization');
if (!token) {
throw createError({ statusCode: 401, message: 'Unauthorized' });
}
event.context.user = verifyToken(token);
});
51. Nuxt 如何处理 SEO 和 Meta?
<script setup>
// 使用 useHead
useHead({
title: '页面标题',
meta: [
{ name: 'description', content: '页面描述' },
{ property: 'og:title', content: 'Open Graph 标题' }
],
link: [
{ rel: 'canonical', href: 'https://example.com/page' }
]
});
// 使用 useSeoMeta(类型安全)
useSeoMeta({
title: '页面标题',
description: '页面描述',
ogTitle: 'Open Graph 标题',
ogDescription: 'Open Graph 描述',
twitterCard: 'summary_large_image'
});
// 动态数据
const { data } = await useFetch('/api/post/1');
useHead({
title: data.value?.title,
meta: [
{ name: 'description', content: data.value?.description }
]
});
</script>
52. 什么是 Nuxt 模块(Modules)?
答案要点:
- 扩展 Nuxt 功能的插件包
- 常用模块:
@nuxtjs/tailwindcss- Tailwind CSS 集成@nuxtjs/i18n- 国际化@nuxtjs/seo- SEO 优化@pinia/nuxt- 状态管理
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
'@nuxtjs/i18n'
],
i18n: {
locales: ['en', 'zh'],
defaultLocale: 'zh'
}
});
Node.js 资料
🔧 核心基础
53. Node.js 是什么?特点?
答案要点:
- 基于 Chrome V8 引擎的 JavaScript 运行时
- 核心特点:
- 事件驱动(Event-driven)
- 非阻塞 I/O(Non-blocking I/O)
- 单线程 + 事件循环
- 跨平台
- 丰富的 npm 生态
54. 事件循环(Event Loop)的工作原理?
答案要点:
┌───────────────────────────┐
┌─>│ timers │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ pending callbacks │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
│ │ idle, prepare │
│ └─────────────┬─────────────┘ ┌──────────────┐
│ ┌─────────────┴─────────────┐ │ incoming: │
│ │ poll │<─────┤ connections │
│ └─────────────┬─────────────┘ │ data, etc. │
│ ┌─────────────┴─────────────┐ └──────────────┘
│ │ check │
│ └─────────────┬─────────────┘
│ ┌─────────────┴─────────────┐
└──┤ close callbacks │
└───────────────────────────┘
阶段说明:
- timers: 执行 setTimeout/setInterval 回调
- pending callbacks: 执行系统操作的回调
- idle/prepare: Node 内部使用
- poll: 检索新的 I/O 事件,执行 I/O 回调
- check: 执行 setImmediate 回调
- close callbacks: 执行 close 事件回调
执行顺序示例:
console.log('1'); // 同步
setTimeout(() => console.log('2'), 0); // 宏任务 - timers
setImmediate(() => console.log('3')); // 宏任务 - check
Promise.resolve().then(() => console.log('4')); // 微任务
process.nextTick(() => console.log('5')); // nextTick
console.log('6'); // 同步
// 输出:1 → 6 → 5 → 4 → 2 → 3
55. 微任务和宏任务的区别?
| 特性 | 微任务 (Microtask) | 宏任务 (Macrotask) |
|---|---|---|
| 包含 | Promise.then, queueMicrotask, process.nextTick | setTimeout, setInterval, setImmediate, I/O |
| 执行时机 | 当前操作完成后,下一个宏任务前 | 事件循环的特定阶段 |
| 优先级 | 高 | 相对较低 |
56. CommonJS vs ES Modules?
| 特性 | CommonJS (CJS) | ES Modules (ESM) |
|---|---|---|
| 语法 | require/module.exports | import/export |
| 加载方式 | 运行时同步加载 | 编译时静态分析 |
| 加载时机 | 运行时 | 解析阶段 |
| 动态导入 | 原生支持 | import() 函数 |
| 循环依赖 | 部分支持 | 更好支持 |
| 文件扩展名 | .js/.cjs | .mjs / package.json "type": "module" |
// CommonJS
const fs = require('fs');
module.exports = { foo: 'bar' };
// ES Modules
import fs from 'fs';
import { readFile } from 'fs/promises';
export const foo = 'bar';
export default mainFunction;
// 动态导入(ESM)
const module = await import('./module.js');
57. Buffer 是什么?
答案要点:
- 用于处理二进制数据的类
- 类似整数数组,但大小固定
- 在 TCP 流、文件操作等场景使用
// 创建 Buffer
const buf1 = Buffer.alloc(10); // 分配 10 字节
const buf2 = Buffer.from('Hello'); // 从字符串创建
const buf3 = Buffer.from([1, 2, 3]); // 从数组创建
// 操作
buf2.toString(); // 'Hello'
Buffer.concat([buf1, buf2]); // 合并
58. Stream 是什么?类型?
答案要点:
- 流是处理数据的一种方式,分块处理,节省内存
- 四种类型:
- Readable: 可读流(fs.createReadStream)
- Writable: 可写流(fs.createWriteStream)
- Duplex: 双工流(net.Socket)
- Transform: 转换流(zlib.createGzip)
const fs = require('fs');
const zlib = require('zlib');
// 管道:读取 → 压缩 → 写入
fs.createReadStream('input.txt')
.pipe(zlib.createGzip())
.pipe(fs.createWriteStream('input.txt.gz'));
🌐 进阶特性
59. Cluster 模块是什么?
答案要点:
- 创建多进程集群,利用多核 CPU
- 主进程(Master)管理工作进程(Worker)
- 工作进程共享服务器端口
const cluster = require('cluster');
const http = require('http');
const os = require('os');
if (cluster.isMaster) {
// 启动多个工作进程
const numCPUs = os.cpus().length;
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
// 工作进程创建 HTTP 服务器
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello World');
}).listen(8000);
}
60. 如何处理 Node.js 错误?
答案要点:
// 1. 同步错误 try-catch
try {
riskyOperation();
} catch (error) {
console.error('Error:', error);
}
// 2. 异步错误(回调)
fs.readFile('file.txt', (err, data) => {
if (err) {
console.error('Read error:', err);
return;
}
// 处理 data
});
// 3. Promise 错误
doSomething()
.then(result => process(result))
.catch(error => console.error('Promise error:', error));
// 4. async/await
try {
const result = await doSomething();
} catch (error) {
console.error('Async error:', error);
}
// 5. 全局错误捕获
process.on('uncaughtException', (err) => {
console.error('Uncaught Exception:', err);
process.exit(1);
});
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection:', reason);
});
61. Node.js 如何调试?
答案要点:
# 1. 内置调试器
node inspect app.js
node --inspect app.js # Chrome DevTools
node --inspect-brk app.js # 首行断点
# 2. 使用 debugger 语句
function test() {
debugger; // 在此处断点
console.log('test');
}
# 3. console 方法
console.log('Debug info');
console.table([{ name: 'John', age: 30 }]);
console.time('timer');
// ... 代码
console.timeEnd('timer');
62. 如何优化 Node.js 性能?
答案要点:
- 使用 Cluster/Worker Threads 利用多核
- 启用 HTTP Keep-Alive
- 使用缓存(Redis/Memcached)
- 数据库连接池
- 使用 Stream 处理大文件
- 使用 CDN 分发静态资源
- 压缩响应(gzip/brotli)
- APM 工具监控性能瓶颈
NestJS 资料
🏗️ 架构基础
63. NestJS 是什么?核心设计思想?
答案要点:
- 用于构建高效、可扩展的 Node.js 服务端应用的框架
- 核心设计思想:
- 模块化架构(Modular)
- 依赖注入(Dependency Injection)
- 装饰器驱动的开发
- 支持 TypeScript
- 受 Angular 启发
64. 核心概念:Module、Controller、Provider
// 模块 (Module) - 组织应用的基本单元
@Module({
imports: [OtherModule], // 导入其他模块
controllers: [UserController], // 声明控制器
providers: [UserService], // 声明提供者(服务)
exports: [UserService] // 导出供其他模块使用
})
export class UserModule {}
// 控制器 (Controller) - 处理请求
@Controller('users')
export class UserController {
constructor(private readonly userService: UserService) {}
@Get()
findAll() {
return this.userService.findAll();
}
@Get(':id')
findOne(@Param('id') id: string) {
return this.userService.findOne(id);
}
@Post()
create(@Body() createUserDto: CreateUserDto) {
return this.userService.create(createUserDto);
}
}
// 提供者/服务 (Provider) - 业务逻辑
@Injectable()
export class UserService {
private users = [];
findAll() {
return this.users;
}
findOne(id: string) {
return this.users.find(user => user.id === id);
}
create(createUserDto: CreateUserDto) {
const user = { id: Date.now().toString(), ...createUserDto };
this.users.push(user);
return user;
}
}
65. 依赖注入(DI)是如何工作的?
答案要点:
- IoC 容器: NestJS 内置控制反转容器
- 注入方式:
- 构造函数注入(推荐)
- 属性注入
- 作用域:
- DEFAULT(单例)
- REQUEST(每次请求新实例)
- TRANSIENT(每次注入新实例)
// 构造函数注入
@Injectable()
export class UserService {
constructor(
private readonly httpService: HttpService,
@Inject('DATABASE') private readonly db: Database,
@Optional() private readonly cache?: CacheService
) {}
}
// 自定义 Provider
@Module({
providers: [
{
provide: 'DATABASE',
useValue: { host: 'localhost', port: 5432 }
},
{
provide: UserService,
useClass: MockUserService // 测试时替换实现
},
{
provide: 'ASYNC_CONFIG',
useFactory: async () => {
return await loadConfig();
}
}
]
})
66. 装饰器汇总
// 模块装饰器
@Module({})
@Global() // 全局模块
// 控制器装饰器
@Controller('path')
@Get() @Post() @Put() @Patch() @Delete() @Options() @Head() @All()
// 参数装饰器
@Param('id') // URL 参数
@Query('search') // 查询参数
@Body() // 请求体
@Headers() // 请求头
@Ip() // 客户端 IP
@Req() @Res() // 请求/响应对象
// 方法装饰器
@HttpCode(201) // 设置状态码
@Header('X-Key', 'value') // 设置响应头
@Redirect('/url', 301) // 重定向
// 其他装饰器
@Injectable() // 标记为可注入
@Catch() // 异常过滤器
@UseGuards() // 使用守卫
@UseInterceptors() // 使用拦截器
@UsePipes() // 使用管道
🛡️ 进阶特性
67. 管道(Pipe)是什么?常用管道?
答案要点:
- 在控制器方法处理之前对输入数据进行转换和验证
- 常用管道:
ValidationPipe- 数据验证ParseIntPipe- 字符串转数字ParseBoolPipe- 字符串转布尔ParseArrayPipe- 解析数组
// 内置管道使用
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) {
return this.service.findOne(id);
}
// 自定义管道
@Injectable()
export class ParseOptionalIntPipe implements PipeTransform {
transform(value: string | undefined) {
if (value === undefined) return undefined;
const val = parseInt(value, 10);
if (isNaN(val)) {
throw new BadRequestException('Validation failed');
}
return val;
}
}
// DTO 验证
import { IsString, IsEmail, MinLength } from 'class-validator';
export class CreateUserDto {
@IsString()
@MinLength(2)
name: string;
@IsEmail()
email: string;
}
// 全局启用验证
app.useGlobalPipes(new ValidationPipe({
whitelist: true, // 去除未定义的属性
forbidNonWhitelisted: true, // 拒绝未定义的属性
transform: true // 自动类型转换
}));
68. 守卫(Guard)和拦截器(Interceptor)的区别?
| 特性 | Guard(守卫) | Interceptor(拦截器) |
|---|---|---|
| 用途 | 权限控制、认证 | 数据转换、日志、缓存 |
| 执行时机 | 控制器方法之前 | 方法前后都可 |
| 返回值 | boolean 或 Promise | Observable 或修改后的数据 |
// Guard - 认证守卫
@Injectable()
export class JwtAuthGuard implements CanActivate {
constructor(private jwtService: JwtService) {}
canActivate(context: ExecutionContext): boolean {
const request = context.switchToHttp().getRequest();
const token = request.headers.authorization?.split(' ')[1];
try {
const payload = this.jwtService.verify(token);
request.user = payload;
return true;
} catch {
return false;
}
}
}
// 使用
@Controller('users')
@UseGuards(JwtAuthGuard)
export class UserController {}
// Interceptor - 转换响应
@Injectable()
export class TransformInterceptor<T> implements NestInterceptor<T, Response<T>> {
intercept(context: ExecutionContext, next: CallHandler): Observable<Response<T>> {
return next.handle().pipe(
map(data => ({
data,
code: 200,
message: 'success',
timestamp: new Date().toISOString()
}))
);
}
}
// 日志拦截器
@Injectable()
export class LoggingInterceptor implements NestInterceptor {
intercept(context: ExecutionContext, next: CallHandler): Observable<any> {
const start = Date.now();
return next.handle().pipe(
tap(() => {
console.log(`Request took ${Date.now() - start}ms`);
})
);
}
}
69. 异常过滤器(Exception Filter)
// 全局异常过滤器
@Catch()
export class AllExceptionsFilter implements ExceptionFilter {
catch(exception: unknown, host: ArgumentsHost) {
const ctx = host.switchToHttp();
const response = ctx.getResponse();
const request = ctx.getRequest();
const status = exception instanceof HttpException
? exception.getStatus()
: HttpStatus.INTERNAL_SERVER_ERROR;
response.status(status).json({
statusCode: status,
timestamp: new Date().toISOString(),
path: request.url,
message: exception instanceof Error ? exception.message : 'Internal error'
});
}
}
// 特定异常过滤器
@Catch(HttpException)
export class HttpExceptionFilter implements ExceptionFilter {
catch(exception: HttpException, host: ArgumentsHost) {
// 处理 HTTP 异常
}
}
// 应用
app.useGlobalFilters(new AllExceptionsFilter());
70. 如何与数据库集成(TypeORM / Prisma)?
TypeORM 示例:
// user.entity.ts
@Entity()
export class User {
@PrimaryGeneratedColumn('uuid')
id: string;
@Column()
name: string;
@Column({ unique: true })
email: string;
@CreateDateColumn()
createdAt: Date;
}
// user.service.ts
@Injectable()
export class UserService {
constructor(
@InjectRepository(User)
private userRepository: Repository<User>
) {}
findAll(): Promise<User[]> {
return this.userRepository.find();
}
async create(createUserDto: CreateUserDto): Promise<User> {
const user = this.userRepository.create(createUserDto);
return this.userRepository.save(user);
}
}
// app.module.ts
@Module({
imports: [
TypeOrmModule.forRoot({
type: 'postgres',
host: 'localhost',
port: 5432,
username: 'user',
password: 'password',
database: 'mydb',
entities: [User],
synchronize: true // 开发环境
}),
TypeOrmModule.forFeature([User])
]
})
Prisma 示例:
// prisma/schema.prisma
model User {
id String @id @default(uuid())
email String @unique
name String?
createdAt DateTime @default(now())
}
// user.service.ts
@Injectable()
export class UserService {
constructor(private prisma: PrismaService) {}
findAll() {
return this.prisma.user.findMany();
}
create(data: CreateUserDto) {
return this.prisma.user.create({ data });
}
}
71. WebSocket 如何实现?
// 安装: npm i @nestjs/websockets @nestjs/platform-socket.io
// gateway
@WebSocketGateway({
cors: { origin: '*' },
namespace: 'events'
})
export class EventsGateway implements OnGatewayConnection, OnGatewayDisconnect {
@WebSocketServer()
server: Server;
handleConnection(client: Socket) {
console.log(`Client connected: ${client.id}`);
}
handleDisconnect(client: Socket) {
console.log(`Client disconnected: ${client.id}`);
}
// 接收消息
@SubscribeMessage('message')
handleMessage(@MessageBody() data: string): WsResponse<string> {
return { event: 'message', data: `Echo: ${data}` };
}
// 广播消息
@SubscribeMessage('broadcast')
handleBroadcast(@MessageBody() data: any) {
this.server.emit('broadcast', data);
}
}
72. 微服务如何构建?
// 微服务传输方式:TCP、Redis、NATS、RabbitMQ、Kafka 等
// main.ts - 启动微服务
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
host: 'localhost',
port: 3001
}
}
);
await app.listen();
}
// 控制器
@Controller()
export class MathController {
@MessagePattern({ cmd: 'sum' }) // 处理消息模式
async sum(data: number[]): Promise<number> {
return data.reduce((a, b) => a + b, 0);
}
@EventPattern('user_created') // 处理事件
async handleUserCreated(data: Record<string, unknown>) {
console.log('User created:', data);
}
}
// 客户端调用
@Injectable()
export class MathService {
@Client({
transport: Transport.TCP,
options: { host: 'localhost', port: 3001 }
})
private client: ClientTCP;
async calculateSum(numbers: number[]) {
return this.client.send({ cmd: 'sum' }, numbers).toPromise();
}
}
综合面试技巧
💡 面试准备建议
技术深度 vs 广度
| 职级 | 重点 |
|---|---|
| 初级 | 基础概念、API 使用、简单原理 |
| 中级 | 源码理解、性能优化、工程化 |
| 高级 | 架构设计、技术选型、团队管理 |
常见问题类型
- 概念题 - 是什么、有什么区别
- 原理题 - 底层实现、源码分析
- 实践题 - 怎么做、最佳实践
- 场景题 - 遇到问题怎么解决
回答技巧
- STAR 法则: Situation(场景)→ Task(任务)→ Action(行动)→ Result(结果)
- 结构化回答: 先总述,再分点,最后总结
- 举例说明: 结合实际项目经验
项目介绍要点
1. 项目背景和目标
2. 技术栈选型理由
3. 你的职责和贡献
4. 遇到的技术难点及解决方案
5. 项目成果(数据指标)
反问环节建议
- 团队技术栈和架构
- 日常工作流程和协作方式
- 技术挑战和学习机会
- 代码审查和发布流程
📚 学习资源推荐
官方文档
源码学习
- React Fiber 架构
- Vue3 响应式系统
- Node.js 事件循环实现
练习平台
- LeetCode(算法)
- Frontend Masters(系统课程)
- Egghead.io(短视频教程)