10 câu hỏi có thể gặp khi phỏng vấn
Chọn theo kỹ năng và cấp của tin (JavaScript & TypeScript, ReactJS, Node.js). Gợi ý trả lời do Drama Công Ty biên soạn để bạn ôn nhanh, không phải đề của công ty.
01Một trang web dùng càng lâu càng chậm và tốn RAM. Bạn tìm memory leak ở frontend thế nào?JavaScript & TypeScript · Senior
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Memory leak ở frontend thường do thứ gì đó vẫn giữ tham chiếu đến object đáng lẽ đã bỏ đi, nhất là trong SPA vì trang không bao giờ tải lại.
Nguyên nhân hay gặp:
addEventListenertrênwindow/documentmà không gỡ khi component bị huỷ.setInterval, subscription (WebSocket, store) không huỷ.- DOM đã bị gỡ khỏi trang nhưng vẫn được biến JS giữ lại (detached DOM).
- Cache hoặc mảng toàn cục chỉ tăng không giảm.
Cách điều tra với Chrome DevTools:
- Tab Memory: chụp heap snapshot, thực hiện thao tác vài lần, chụp lại, so sánh phần tăng thêm.
- Lọc "Detached" để tìm DOM bị giữ, xem chuỗi retainers để biết ai đang giữ.
- Tab Performance bật Memory để xem heap có giảm sau GC không.
Người phỏng vấn muốn nghe: mỗi tài nguyên đăng ký đều có chỗ huỷ tương ứng (cleanup của effect,
ngOnDestroy,onUnmounted,AbortController).02Core Web Vitals gồm những chỉ số nào? Bạn cải thiện hiệu năng tải trang ra sao?JavaScript & TypeScript · Senior
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Ba chỉ số chính đo trải nghiệm thật của người dùng:
- LCP (Largest Contentful Paint): thời gian hiện phần tử lớn nhất. Cải thiện: tối ưu ảnh (định dạng hiện đại, đúng kích thước, ưu tiên tải ảnh hero), giảm thời gian phản hồi server, cache/CDN, render phía server.
- INP (Interaction to Next Paint, thay FID từ 2024): độ trễ khi tương tác. Cải thiện: chia nhỏ tác vụ JS dài, giảm JS chạy trên main thread, tránh render lại quá nhiều.
- CLS (Cumulative Layout Shift): độ xô lệch bố cục. Cải thiện: khai báo kích thước cho ảnh, video, quảng cáo; tránh chèn nội dung đẩy trang xuống; xử lý font.
Ngoài ra: code splitting và lazy load theo route, bỏ thư viện nặng không cần, nén và cache tài nguyên tĩnh.
Người phỏng vấn muốn nghe: bạn đo bằng dữ liệu người dùng thật (field data) lẫn Lighthouse, và biết điểm Lighthouse không phải là mục tiêu cuối.
03Frontend cần chú ý gì về bảo mật: XSS, CSRF, CORS? Nên lưu access token ở đâu?JavaScript & TypeScript · Senior
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →- XSS: kẻ tấn công chèn script chạy trên trang của bạn. Phòng: framework tự escape khi render; tránh
innerHTML,v-html,dangerouslySetInnerHTMLvới dữ liệu người dùng (nếu bắt buộc thì sanitize); cấu hình Content-Security-Policy. - CSRF: trang lạ khiến trình duyệt gửi request kèm cookie của người dùng. Phòng: cookie
SameSite=LaxhoặcStrict, CSRF token, kiểm traOrigin. - CORS: là cơ chế trình duyệt nới lỏng same-origin policy, do server cấu hình. Nó không phải lớp bảo vệ API khỏi người gọi ngoài trình duyệt.
Lưu token:
localStoragetiện nhưng script XSS nào cũng đọc được.- Cookie
HttpOnly+Secure+SameSitethì JS không đọc được, nhưng phải tính đến CSRF.
Người phỏng vấn muốn nghe: không có chỗ lưu nào an toàn tuyệt đối; chặn XSS mới là việc quan trọng nhất, vì có XSS thì mọi cách lưu đều bị lợi dụng.
- XSS: kẻ tấn công chèn script chạy trên trang của bạn. Phòng: framework tự escape khi render; tránh
04So sánh CSR, SSR, SSG và ISR. Lỗi hydration mismatch là gì và xử lý ra sao?ReactJS · Senior
Gợi ý trả lời
Ôn thêm câu hỏi ReactJS →- CSR: trình duyệt tải JS rồi mới render; nội dung hiện chậm, kém cho SEO.
- SSR: server render HTML cho mỗi request. Dữ liệu luôn mới, tốn tài nguyên server.
- SSG: render sẵn lúc build. Rất nhanh, hợp nội dung ít đổi.
- ISR / revalidate: trang tĩnh được làm mới định kỳ hoặc theo sự kiện.
Hydration là bước React gắn sự kiện vào HTML do server render. Mismatch xảy ra khi lần render đầu ở client khác HTML từ server:
- Dùng
Date.now(),Math.random(), múi giờ,windowhoặclocalStoragetrong lúc render. - HTML lồng sai (
<div>trong<p>), extension trình duyệt sửa DOM.
Cách sửa: chuyển phần chỉ có ở client vào
useEffect, hoặc render component đó chỉ ở client; định dạng ngày giờ bằng múi giờ cố định.Người phỏng vấn muốn nghe: bạn chọn cách render theo từng trang, dựa trên độ tươi dữ liệu và nhu cầu SEO.
05React 19 có những gì mới đáng chú ý? Actions,
useActionStatevàuseOptimisticgiải quyết vấn đề gì?ReactJS · SeniorGợi ý trả lời
Ôn thêm câu hỏi ReactJS →React 19 tập trung vào việc xử lý thao tác bất đồng bộ (gửi form, mutation) gọn hơn:
- Actions: truyền hàm async vào
<form action={fn}>hoặc chạy trongstartTransition. React tự theo dõi trạng thái pending, lỗi, và reset form. useActionState: giữ kết quả của action (thông báo lỗi, dữ liệu trả về) và cờisPending.useFormStatus: component con (nút submit) đọc trạng thái pending của form cha mà không cần truyền props.useOptimistic: hiện kết quả ngay (like, thêm comment) trong lúc chờ server, tự quay về nếu lỗi.use(): đọc Promise hoặc Context, gọi được trong điều kiện.refđược truyền như prop thường, ít cầnforwardRef.
Người phỏng vấn muốn nghe: những API này bỏ bớt code tự quản lý
isLoading,errorvà rollback, và kết hợp tự nhiên với Server Actions trong Next.js.- Actions: truyền hàm async vào
06Thiết kế xử lý job nền (gửi email, đồng bộ dữ liệu) trong hệ thống Node.js thế nào để không mất job và không xử lý trùng?Node.js · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Node.js →Dùng message queue thay vì xử lý ngay trong request: BullMQ (Redis), RabbitMQ hoặc dịch vụ queue của cloud. API đẩy job rồi trả về ngay; worker riêng xử lý.
Những điểm cần thiết kế:
- Retry có backoff (tăng dần thời gian chờ) và giới hạn số lần thử; job vẫn lỗi thì đưa vào dead-letter queue để xem lại.
- Idempotency: hầu hết queue đảm bảo "ít nhất một lần", nên job có thể chạy hai lần. Dùng khoá idempotency hoặc kiểm tra trạng thái trước khi làm (ví dụ email đã gửi chưa).
- Không mất job khi ghi DB: ghi dữ liệu và "sự kiện cần gửi" trong cùng transaction (outbox pattern), rồi một tiến trình khác đẩy sang queue.
- Giới hạn concurrency của worker, timeout cho từng job.
Hay sai: dùng
setTimeouthay mảng trong bộ nhớ làm "queue". Restart hoặc deploy là mất hết job.07Event loop của JavaScript hoạt động thế nào? Đoạn code sau in ra theo thứ tự nào?JavaScript & TypeScript
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →JavaScript chạy trên một thread. Code đồng bộ chạy hết trên call stack trước, sau đó event loop lấy việc từ hàng đợi. Microtask (Promise
.then,await,queueMicrotask) luôn được chạy hết trước khi sang macrotask tiếp theo (setTimeout, sự kiện I/O, sự kiện người dùng).console.log(1); setTimeout(() => console.log(2)); Promise.resolve().then(() => console.log(3)); console.log(4); // 1, 4, 3, 2- Trên trình duyệt, việc render thường diễn ra giữa các macrotask.
- Một vòng lặp đồng bộ dài, hoặc chuỗi microtask không dứt, sẽ làm treo giao diện.
Người phỏng vấn muốn nghe:
setTimeout(fn, 0)không chạy ngay mà chỉ được xếp hàng, và vì sao microtask được ưu tiên.08So sánh
Promise.all,Promise.allSettled,Promise.racevàPromise.any. Xử lý lỗi với async/await thế nào?JavaScript & TypeScriptGợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Cả bốn đều chạy nhiều Promise song song, khác nhau ở cách kết thúc:
all: chờ tất cả thành công; một cái lỗi là reject ngay.allSettled: chờ tất cả xong, trả về trạng thái từng cái; không bao giờ reject.race: lấy kết quả (thành công hay lỗi) của cái xong đầu tiên; hay dùng để đặt timeout.any: lấy cái thành công đầu tiên; chỉ reject khi tất cả đều lỗi.
try { const [user, orders] = await Promise.all([getUser(id), getOrders(id)]); } catch (err) { showError(err); }Hay sai:
awaitlần lượt trong vòng lặp các request không phụ thuộc nhau, khiến tổng thời gian cộng dồn. Ngược lại, gọiPromise.allvới hàng nghìn request cùng lúc có thể làm quá tải server; khi đó cần giới hạn số request đồng thời.09Trong TypeScript,
interfacevàtypekhác nhau thế nào? Phân biệtany,unknownvànever.JavaScript & TypeScriptGợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Cả hai đều mô tả hình dạng object và phần lớn trường hợp dùng thay nhau được.
interfacecó thể gộp khai báo (declaration merging) vàextends; hợp để mô tả object, API công khai.typemô tả được union, tuple, kiểu ánh xạ, kiểu điều kiện:type Status = "idle" | "loading".
Ba kiểu đặc biệt:
any: tắt kiểm tra kiểu, lỗi lọt qua compiler.unknown: nhận mọi giá trị nhưng bắt buộc thu hẹp kiểu trước khi dùng. Hợp cho dữ liệu từJSON.parse, API,catch (e).never: giá trị không bao giờ xảy ra; dùng để bắt thiếu case trongswitch.
function assertNever(x: never): never { throw new Error("Unhandled: " + x); }Hay sai: dùng
as SomeTypeđể ép dữ liệu từ API. Đó chỉ là lời hứa với compiler; muốn chắc chắn phải validate lúc runtime (ví dụ bằng Zod).10Điểm mạnh lớn nhất của bạn là gì?Câu hỏi hành vi & văn hoá
Gợi ý trả lời
Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →Chọn một hai điểm mạnh liên quan tới vị trí, và chứng minh bằng ví dụ thật, không liệt kê tính từ.
Cấu trúc: điểm mạnh, ví dụ ngắn, kết quả, liên hệ với công việc mới.
Câu mẫu: "Điểm mạnh của em là chủ động tìm nguyên nhân gốc. Ở dự án trước, hệ thống thỉnh thoảng bị timeout mà không ai tái hiện được. Em tự đọc log, thêm theo dõi ở các điểm nghi ngờ và tìm ra một truy vấn bị khoá bảng vào giờ cao điểm. Sau khi sửa, lỗi đó không còn xuất hiện. Em nghĩ điều này hữu ích với vị trí bên mình vì hệ thống có lượng truy cập lớn."
Hay sai: "Em chăm chỉ, ham học hỏi, chịu được áp lực" mà không có ví dụ. Ai cũng nói vậy nên không đọng lại gì.
Bạn đã phỏng vấn ở Inspectorio?
Kể lại các vòng và câu hỏi đã gặp (ẩn danh) để người sau ôn đúng trọng tâm.
Chia sẻ kinh nghiệm phỏng vấn