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, Node.js, Python). 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.
01Dùng generics và type narrowing trong TypeScript thế nào? Cho ví dụ discriminated union.JavaScript & TypeScript · Senior
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Generics giúp viết hàm và kiểu dùng lại được mà vẫn giữ thông tin kiểu, thay vì rơi về
any.type Result<T> = | { ok: true; data: T } | { ok: false; error: string }; function show(r: Result<User>) { if (r.ok) return r.data.name; // TS biết có data return r.error; }- Field chung (
ok,type,status) giúp TypeScript thu hẹp kiểu trongif/switch. Đây là cách mô hình hoá trạng thái không thể sai: không có chuyện vừa códatavừa cóerror. - Ràng buộc generic:
<T extends { id: string }>. - Utility types hay dùng:
Partial,Pick,Omit,Record,ReturnType,Awaited. - Type guard tự viết:
function isUser(x: unknown): x is User.
Người phỏng vấn muốn nghe: bạn dùng kiểu để làm trạng thái sai không biểu diễn được, chứ không chỉ để chú thích.
- Field chung (
02Mộ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).03Core 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.
04Bạn mở rộng (scale) một API Node.js thế nào? Graceful shutdown là gì và vì sao cần?Node.js · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Node.js →Node một process chỉ dùng tốt một core, nên scale theo chiều ngang:
- Chạy nhiều process (cluster, PM2) hoặc nhiều container sau load balancer, Kubernetes tự tăng giảm số pod.
- App phải stateless: session, cache, rate limit, lock để ở Redis hoặc DB, không để trong bộ nhớ process.
- WebSocket nhiều instance cần adapter qua Redis pub/sub để gửi tin giữa các instance.
- Đặt giới hạn connection pool DB theo tổng số instance.
Graceful shutdown: khi nhận
SIGTERM(deploy, scale down), ngừng nhận request mới, chờ request đang chạy xong, đóng DB và queue, rồi thoát:process.on("SIGTERM", () => { server.close(async () => { await db.close(); process.exit(0); }); });Hay sai: không xử lý
SIGTERM, mỗi lần deploy lại cắt ngang request và job đang làm dở. Nên đặt thêm timeout buộc thoát nếu chờ quá lâu.05Khi xây dựng API bằng Node.js, bạn chú ý những vấn đề bảo mật nào?Node.js · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Node.js →- Validate mọi input ở biên bằng schema (Zod, Joi,
class-validatortrong NestJS); chỉ nhận field cho phép để tránh mass assignment. - Injection: dùng query có tham số hoặc ORM, không nối chuỗi SQL. Với MongoDB, chặn object toán tử như
{ "$gt": "" }lọt vào điều kiện truy vấn. - Xác thực và phân quyền: kiểm tra quyền trên từng tài nguyên (user này có sở hữu đơn hàng này không), không chỉ kiểm tra đã đăng nhập.
- Rate limiting cho login, OTP, API tốn tài nguyên.
- Header bảo mật (Helmet), CORS chỉ mở cho origin cần thiết.
- Secret để trong biến môi trường hoặc secret manager, không commit; không log token, mật khẩu.
- Dependency: chạy
npm audithoặc công cụ quét trong CI, khoá phiên bản bằng lockfile.
Người phỏng vấn muốn nghe: lỗi phân quyền theo đối tượng (IDOR) rất phổ biến, và bạn biết cách phòng nó.
- Validate mọi input ở biên bằng schema (Zod, Joi,
06Một API viết bằng Python (Django hoặc FastAPI) phản hồi chậm. Bạn tối ưu theo thứ tự nào?Python · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Python →Đo trước, tối ưu chỗ tốn nhất trước. Phần lớn trường hợp nút thắt là DB và gọi mạng, không phải tốc độ của Python.
- Đo: APM hoặc tracing (OpenTelemetry) để biết thời gian nằm ở DB, API ngoài hay code. Profile bằng
py-spy(gắn vào process đang chạy) hoặccProfile. - DB: xử lý N+1, thêm index phù hợp, chỉ lấy cột cần (
only,values), phân trang. - Cache: Redis cho dữ liệu đọc nhiều, ít đổi; nhớ chiến lược invalidate.
- Việc nặng hoặc không cần trả ngay (gửi email, xuất file): đẩy sang Celery hoặc queue.
- Gọi nhiều API ngoài: chạy song song, đặt timeout.
- Cuối cùng mới tới tối ưu thuật toán, hoặc đưa đoạn nặng CPU sang thư viện C hay service khác.
Hay sai: viết lại sang async hoặc đổi ngôn ngữ trước khi biết thời gian thực sự bị tiêu ở đâu.
- Đo: APM hoặc tracing (OpenTelemetry) để biết thời gian nằm ở DB, API ngoài hay code. Profile bằng
07Frontend 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
08Phân biệt
var,letvàconst. Hoisting và temporal dead zone là gì?JavaScript & TypeScript · JuniorGợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →varcó phạm vi hàm, cònlet/constcó phạm vi block ({}).constkhông cho gán lại biến, nhưng object hay array bên trong vẫn sửa được.- Hoisting: khai báo được "kéo" lên đầu phạm vi.
varđược khởi tạo sẵn làundefined, nên dùng trước khi khai báo không báo lỗi. let/constcũng được hoist nhưng chưa khởi tạo. Truy cập trước dòng khai báo némReferenceError; khoảng đó gọi là temporal dead zone.- Function declaration được hoist cả phần thân, nên gọi được trước khi định nghĩa.
console.log(a); // undefined console.log(b); // ReferenceError var a = 1; let b = 2;Người phỏng vấn muốn nghe: mặc định dùng
const, cần gán lại mới dùnglet, và gần như không dùngvartrong code mới.- Hoisting: khai báo được "kéo" lên đầu phạm vi.
09
==và===khác nhau thế nào? Những giá trị nào là falsy?JavaScript & TypeScript · JuniorGợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →===so sánh cả kiểu lẫn giá trị.==ép kiểu trước khi so, nên cho ra kết quả khó đoán:"0" == 0làtrue,[] == falsecũngtrue.- Các giá trị falsy:
false,0,-0,0n,"",null,undefined,NaN. Mọi thứ khác là truthy, kể cả[],{}và"0". NaN === NaNlàfalse; dùngNumber.isNaN(x).- Ngoại lệ hay được chấp nhận:
x == nullđể bắt cảnulllẫnundefined.
Hay sai: viết
const page = input || 1. Khi người dùng nhập0, giá trị bị thay bằng1. Dùng nullish coalescinginput ?? 1để chỉ thay khi lànullhoặcundefined.- Các giá trị falsy:
10Bạn nghĩ sao về việc làm thêm giờ (OT)?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á →Trả lời thẳng thắn và cân bằng: sẵn sàng khi thật sự cần, nhưng không coi OT kéo dài là bình thường.
Câu mẫu: "Em sẵn sàng làm thêm khi có việc gấp như sự cố production hay trước một đợt release quan trọng. Nhưng nếu OT diễn ra thường xuyên, em nghĩ cần xem lại cách estimate hoặc phạm vi, và em sẽ chủ động nêu điều đó với team. Em cũng muốn hỏi thêm: ở team mình OT thường xảy ra trong trường hợp nào và được tính như thế nào ạ?"
Đây cũng là lúc bạn tìm hiểu ngược: OT có được trả lương hoặc nghỉ bù theo quy định không, tần suất ra sao. Câu trả lời của họ cho bạn biết nhiều về văn hoá công ty.
Hay sai: hứa "OT thoải mái" để lấy điểm, rồi vào làm mới thấy không chịu nổi.
Bạn đã phỏng vấn ở Sqreem Technologies (VN) Pte. Ltd.?
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