Dưới đây là danh sách 50 câu hỏi phỏng vấn chuyên sâu về NodeJS và NextJS, kèm theo lời giải chi tiết và code demo để bạn có thể chuẩn bị tốt nhất cho buổi phỏng vấn.
PHẦN 1: NODEJS (25 CÂU)
1. Event Loop trong NodeJS hoạt động như thế nào?
Lời giải: NodeJS là single-threaded nhưng có thể xử lý non-blocking I/O bằng cách chuyển các tác vụ nặng (file hệ thống, mạng) cho hệ điều hành hoặc Thread Pool. Event Loop có các pha chính: Timers, I/O Callbacks, Idle/Prepare, Poll, Check, và Close Callbacks.
Code Demo:
console.log('Start');
setTimeout(() => console.log('Timeout'), 0);
setImmediate(() => console.log('Immediate'));
process.nextTick(() => console.log('Next Tick'));
console.log('End');
// Thứ tự: Start -> End -> Next Tick -> Timeout -> Immediate
2. Phân biệt process.nextTick() và setImmediate()?
Lời giải:
process.nextTick()thực thi ngay sau khi hoạt động hiện tại kết thúc, trước khi Event Loop tiếp tục sang pha tiếp theo.setImmediate()được thực thi ở pha "Check" của Event Loop.Code Demo:
setImmediate(() => console.log('Immediate'));
process.nextTick(() => console.log('Next Tick'));
// Next Tick luôn chạy trước Immediate
3. Stream trong NodeJS là gì? Có mấy loại?
Lời giải: Stream là cách xử lý dữ liệu lớn bằng cách chia nhỏ thành các "chunk" thay vì đọc toàn bộ vào bộ nhớ. Có 4 loại: Readable, Writable, Duplex (cả đọc và ghi), và Transform (thay đổi dữ liệu khi đọc/ghi).
Code Demo:
const fs = require('fs');
const readableStream = fs.createReadStream('largefile.txt');
const writableStream = fs.createWriteStream('output.txt');
readableStream.pipe(writableStream);
4. Middleware trong ExpressJS là gì?
Lời giải: Là các hàm có quyền truy cập vào đối tượng request (req), response (res) và hàm
next()để chuyển tiếp sang middleware kế tiếp. Dùng để log, auth, parse data...Code Demo:
app.use((req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
});
5. Làm thế nào để xử lý Uncaught Exceptions?
Lời giải: Sử dụng
process.on('uncaughtException'). Tuy nhiên, tốt nhất là nên restart process vì ứng dụng lúc này có thể ở trạng thái không ổn định.Code Demo:
process.on('uncaughtException', (err) => {
console.error('Lỗi chưa được xử lý:', err);
process.exit(1);
});
6. Cluster Module dùng để làm gì?
Lời giải: Cho phép tận dụng hệ thống đa nhân (multi-core) bằng cách tạo ra các worker processes con dùng chung cổng mạng.
Code Demo:
const cluster = require('cluster');
const http = require('http');
if (cluster.isMaster) {
for (let i = 0; i < require('os').cpus().length; i++) cluster.fork();
} else {
http.createServer((req, res) => res.end('Hello')).listen(8000);
}
7. Buffer trong NodeJS là gì?
Lời giải: Buffer là một vùng bộ nhớ tạm thời dùng để lưu trữ dữ liệu nhị phân thô, thường dùng khi làm việc với file hoặc stream.
Code Demo:
const buf = Buffer.from('Hello', 'utf8');
console.log(buf.toJSON()); // { type: 'Buffer', data: [ 72, 101, 108, 108, 111 ] }
8. Worker Threads là gì? Khác gì với Cluster?
Lời giải: Cluster tạo ra nhiều Process (tốn RAM hơn), còn Worker Threads chạy nhiều luồng trong cùng một Process (dùng chung bộ nhớ). Dùng Worker Threads cho các tác vụ tính toán nặng (CPU intensive).
Code Demo:
const { Worker, isMainThread } = require('worker_threads');
if (isMainThread) {
new Worker(__filename);
} else {
console.log('Chạy trong worker thread');
}
9. Giải thích cơ chế của EventEmitter?
Lời giải: Là core module cho phép các đối tượng phát ra (emit) các sự kiện có tên và đăng ký các hàm lắng nghe (listener).
Code Demo:
const EventEmitter = require('events');
const myEmitter = new EventEmitter();
myEmitter.on('greet', (name) => console.log('Hello ' + name));
myEmitter.emit('greet', 'Diep');
10. Tại sao nên dùng require thay vì import (hoặc ngược lại)?
Lời giải:
requirelà CommonJS (đồng bộ, runtime),importlà ES Modules (bất đồng bộ, compile-time). NodeJS hiện tại đã hỗ trợ tốt cả hai, nhưng ESM là tiêu chuẩn mới.Code Demo:
// CommonJS
const fs = require('fs');
// ESM (cần "type": "module" trong package.json)
import fs from 'fs';
11. package-lock.json dùng để làm gì?
Lời giải: Đảm bảo tính nhất quán của các dependency tree giữa các môi trường cài đặt khác nhau bằng cách khóa chính xác phiên bản của từng sub-dependency.
12. Cách ngăn chặn Callback Hell?
Lời giải: Sử dụng Promises hoặc Async/Await.
Code Demo:
async function getData() {
try {
const res = await fetch('api/data');
const data = await res.json();
return data;
} catch (err) { console.error(err); }
}
13. Phân biệt dependencies và devDependencies?
Lời giải:
dependencieslà các gói cần để chạy app ở production.devDependencieschỉ cần cho quá trình phát triển (như nodemon, jest, typescript).
14. Làm thế nào để bảo mật ứng dụng Express?
Lời giải: Sử dụng thư viện
helmetđể thiết lập các HTTP headers bảo mật, giới hạn rate-limit, validate dữ liệu đầu vào.Code Demo:
const helmet = require('helmet');
app.use(helmet());
15. Garbage Collection trong NodeJS hoạt động như thế nào?
Lời giải: V8 engine sử dụng thuật toán "Mark-and-Sweep". Nó đánh dấu các object còn tham chiếu và giải phóng những object không còn được truy cập từ gốc (root).
16. REPL trong NodeJS là gì?
Lời giải: Viết tắt của Read-Eval-Print Loop. Là môi trường dòng lệnh tương tác để chạy code JS trực tiếp (gõ lệnh
nodetrên terminal).
17. Libuv là gì?
Lời giải: Là thư viện C++ giúp NodeJS xử lý các tác vụ bất đồng bộ (I/O, Thread pool). Nó là trái tim xử lý Event Loop.
18. NVM là gì? Tại sao nên dùng?
Lời giải: Node Version Manager. Giúp cài đặt và chuyển đổi giữa nhiều phiên bản Node trên cùng một máy tính dễ dàng.
19. Làm sao để đọc file lớn mà không làm treo app?
Lời giải: Sử dụng Stream thay vì
fs.readFile.Code Demo:
fs.createReadStream('big.file').on('data', (chunk) => {
// xử lý từng phần
});
20. JWT (JSON Web Token) gồm những phần nào?
Lời giải: Gồm 3 phần phân tách bởi dấu chấm: Header (thuật toán), Payload (dữ liệu người dùng), Signature (chữ ký bảo mật).
21. module.exports và exports khác nhau thế nào?
Lời giải:
module.exportslà đối tượng thực sự được trả về.exportschỉ là một tham chiếu (reference) đếnmodule.exports. Nếu bạn gánexports = {}thì nó sẽ mất tham chiếu.
22. Tại sao NodeJS không phù hợp cho tác vụ tính toán CPU nặng (như render video)?
Lời giải: Vì nó single-threaded. Tác vụ nặng sẽ block Event Loop, khiến các request khác không được xử lý. Giải pháp là dùng Worker Threads.
23. Cách quản lý biến môi trường trong Node?
Lời giải: Dùng gói
dotenvvà file.env.Code Demo:
require('dotenv').config();
console.log(process.env.DB_URL);
24. Socket.io là gì?
Lời giải: Thư viện hỗ trợ giao tiếp hai chiều (bi-directional) thời gian thực giữa client và server dựa trên WebSockets.
25. Sự khác biệt giữa spawn và exec trong child_process?
Lời giải:
spawntrả về stream (dùng cho dữ liệu lớn),exectrả về buffer (đợi lệnh chạy xong mới trả kết quả, giới hạn dung lượng mặc định 200kb).
PHẦN 2: NEXTJS (25 CÂU)
26. NextJS là gì? Tại sao nên dùng NextJS thay vì React thuần?
Lời giải: NextJS là Framework cho React hỗ trợ SSR, SSG, Routing tự động và Image Optimization. Giúp SEO tốt hơn và hiệu năng cao hơn.
27. Phân biệt SSR và SSG?
Lời giải:
SSR (Server-Side Rendering): Tạo HTML mỗi khi có request. Phù hợp dữ liệu thay đổi liên tục.
SSG (Static Site Generation): Tạo HTML một lần duy nhất lúc Build. Phù hợp blog, trang tin tức.
28. ISR (Incremental Static Regeneration) là gì?
Lời giải: Cho phép cập nhật trang tĩnh sau khi đã build mà không cần build lại toàn bộ site.
Code Demo:
export async function getStaticProps() {
return {
props: { data },
revalidate: 60, // Cập nhật lại sau mỗi 60 giây
};
}
29. App Router (Next 13+) khác gì Pages Router?
Lời giải: App Router sử dụng React Server Components, hỗ trợ lồng layout (nested layouts) và mặc định các component là Server Components.
30. Server Components là gì?
Lời giải: Là component chỉ render ở Server, không gửi JS về Client. Giúp giảm bundle size.
Code Demo:
// Mặc định là Server Component trong App Router
async function Page() {
const data = await fetchData(); // Gọi DB trực tiếp được
return <div>{data.title}</div>;
}
31. Khi nào dùng "use client"?
Lời giải: Khi component cần dùng React Hooks (
useState,useEffect), dùng Browser API hoặc các sự kiện tương tác (onClick).
32. getStaticPaths dùng để làm gì?
Lời giải: Trong Pages Router, nó định nghĩa danh sách các dynamic routes (ví dụ
/post/[id]) cần được render tĩnh lúc build.
33. Image Component trong NextJS có lợi ích gì?
Lời giải: Tự động resize ảnh theo thiết bị, lazy loading, và chống Cumulative Layout Shift (CLS).
Code Demo:
import Image from 'next/image';
<Image src="/logo.png" width={500} height={500} alt="Logo" />
34. Làm thế nào để fetch data trong App Router?
Lời giải: Dùng
fetchtrực tiếp trong Server Component với cú phápasync/await. NextJS mở rộng hàmfetchđể hỗ trợ caching.Code Demo:
const res = await fetch('https://api...', { cache: 'no-store' }); // Tương đương SSR
35. Middleware trong NextJS nằm ở đâu?
Lời giải: File
middleware.tsnằm ở thư mục gốc. Dùng để xử lý logic trước khi request hoàn tất (auth, redirect).
36. Link component trong NextJS khác gì thẻ <a>?
Lời giải:
Linkhỗ trợ client-side chuyển trang mà không load lại trang và tự động pre-fetch code của trang đích.
37. SEO trong NextJS App Router xử lý như thế nào?
Lời giải: Sử dụng object
metadatahoặc hàmgenerateMetadata.Code Demo:
export const metadata = { title: 'Trang chủ', description: '...' };
38. Cấu trúc folder app/ cơ bản?
Lời giải:
page.tsx(nội dung trang),layout.tsx(giao diện chung),loading.tsx(trạng thái chờ),error.tsx(xử lý lỗi).
39. Làm sao để tạo API Route trong NextJS?
Lời giải: Tạo file
route.tstrong folderapi/.Code Demo:
export async function GET() {
return Response.json({ message: 'Hello' });
}
40. NextJS tự động tối ưu Font như thế nào?
Lời giải: Sử dụng
next/font. Nó tự động tải font về lúc build và phục vụ từ cùng domain để tránh request bên thứ 3 (Google Fonts).
41. Hydration là gì?
Lời giải: Là quá trình React ở Client "gắn" các sự kiện (event handlers) vào HTML tĩnh đã được server trả về để trang web có thể tương tác.
42. Làm thế nào để bắt lỗi Global trong NextJS?
Lời giải: Sử dụng file
global-error.tsxở cấp cao nhất của thư mụcapp/.
43. dynamic import trong NextJS dùng khi nào?
Lời giải: Để code-splitting, chỉ load component khi cần thiết (ví dụ: Modal hoặc đồ thị nặng).
Code Demo:
import dynamic from 'next/dynamic';
const HeavyComp = dynamic(() => import('./HeavyComponent'), { ssr: false });
44. Cách xử lý Authentication trong NextJS?
Lời giải: Phổ biến nhất là dùng
NextAuth.js(Auth.js) hỗ trợ OAuth, Credentials, và Session Management.
45. Biến môi trường ở Client Side trong NextJS?
Lời giải: Phải có tiền tố
NEXT_PUBLIC_. Ví dụ:NEXT_PUBLIC_API_KEY.
46. parallel routes là gì?
Lời giải: Cho phép render nhiều trang trong cùng một layout (ví dụ: Dashboard có cả bảng tin và tin nhắn cùng lúc). Sử dụng folder
@slot.
47. intercepting routes là gì?
Lời giải: Cho phép load một route bên trong route hiện tại (ví dụ: click vào ảnh hiện Modal thay vì chuyển trang hoàn toàn).
48. Cache trong NextJS hoạt động như thế nào?
Lời giải: Có 4 tầng cache: Request Memoization, Data Cache, Full Route Cache, và Router Cache.
49. Làm thế nào để ép buộc một route luôn là Dynamic (không cache)?
Lời giải: Thêm
export const dynamic = 'force-dynamic'vào file page hoặc layout.
50. Deployment NextJS ở đâu là tốt nhất?
Lời giải: Vercel (nhà sáng lập NextJS) là tốt nhất vì hỗ trợ full các tính năng như Edge Functions, ISR và tối ưu hóa ảnh tự động.