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, SQL & Database, Tester / QA). 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.
01Debounce và throttle khác nhau thế nào? Mỗi cái dùng trong trường hợp nào?JavaScript & TypeScript
Gợi ý trả lời
Ôn thêm câu hỏi JavaScript & TypeScript →Cả hai giới hạn số lần một hàm chạy khi sự kiện bắn liên tục.
- Debounce: chỉ chạy sau khi sự kiện ngừng một khoảng thời gian. Hợp với ô tìm kiếm gợi ý (gõ xong mới gọi API), validate form, resize xong mới tính lại layout.
- Throttle: chạy tối đa một lần mỗi khoảng thời gian. Hợp với scroll, kéo thả, theo dõi vị trí chuột.
function debounce(fn, ms) { let timer; return (...args) => { clearTimeout(timer); timer = setTimeout(() => fn(...args), ms); }; }Hay sai: tạo hàm debounce mới mỗi lần render (trong React), khiến timer bị reset liên tục và debounce không có tác dụng. Với ô tìm kiếm, nhớ huỷ request cũ (
AbortController) để kết quả cũ không đè kết quả mới.02Dù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 (
03Mộ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).04Deadlock trong database xảy ra thế nào và xử lý ra sao?SQL & Database · Senior
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →Deadlock là khi hai transaction giữ khoá mà bên kia cần và chờ nhau mãi. DB tự phát hiện, chọn một transaction làm nạn nhân và rollback nó.
Ví dụ: T1 khoá dòng A rồi muốn B, cùng lúc T2 khoá B rồi muốn A.
Cách giảm deadlock:
- Luôn khoá tài nguyên theo cùng một thứ tự (vd. sắp xếp theo
idtrước khi update nhiều dòng). - Giữ transaction ngắn, không chờ I/O bên ngoài khi đang giữ khoá.
- Có index phù hợp để câu
UPDATE/DELETEkhông khoá quá nhiều dòng. - Ứng dụng bắt lỗi deadlock và retry có giới hạn.
Khi điều tra: MySQL dùng
SHOW ENGINE INNODB STATUS, PostgreSQL xem log (deadlock được ghi kèm câu lệnh) vàpg_locks.Người phỏng vấn muốn nghe: bạn coi retry là bình thường nhưng vẫn tìm gốc rễ ở thứ tự khoá.
- Luôn khoá tài nguyên theo cùng một thứ tự (vd. sắp xếp theo
05Khi nào chọn NoSQL (MongoDB, Redis…) thay vì SQL? Trade-off là gì?SQL & Database · Senior
Gợi ý trả lời
Ôn thêm câu hỏi SQL & Database →Chọn theo mô hình truy cập dữ liệu, không theo xu hướng. SQL mạnh ở quan hệ, ràng buộc và transaction; NoSQL mạnh ở schema linh hoạt, mô hình dữ liệu đặc thù hoặc scale ngang dễ hơn.
- Document (MongoDB): dữ liệu dạng cây, đọc nguyên khối theo một khoá, schema thay đổi thường xuyên.
- Key-value (Redis): cache, session, rate limit, bộ đếm, hàng đợi nhỏ; dữ liệu chủ yếu nằm trong RAM.
- Wide-column, time-series, search engine: ghi khối lượng lớn, log, tìm kiếm full-text.
Trade-off: JOIN và transaction nhiều document hạn chế hoặc đắt hơn, ràng buộc dữ liệu chuyển sang tầng ứng dụng, và phải thiết kế theo query ngay từ đầu.
Người phỏng vấn muốn nghe: nhiều hệ thống dùng kết hợp, vd. PostgreSQL làm nguồn sự thật, Redis làm cache. PostgreSQL với
JSONBcũng đủ cho nhiều nhu cầu "schema linh hoạt".06Bạn chọn framework automation (Selenium, Playwright, Cypress…) dựa trên tiêu chí nào?Tester / QA · Senior
Gợi ý trả lời
Ôn thêm câu hỏi Tester / QA →Không có framework tốt nhất, chỉ có cái hợp với sản phẩm và team.
- Loại ứng dụng: web, mobile (Appium hoặc framework native), desktop, API.
- Ngôn ngữ của team: nên trùng với dev để họ cùng review và viết test.
- Trình duyệt cần hỗ trợ, có cần nhiều tab/domain, iframe, file upload.
- Tốc độ và độ ổn định: auto-wait, chạy song song, retry, trace khi lỗi.
- Tích hợp CI/CD, báo cáo, chạy trên container.
- Cộng đồng, tài liệu, khả năng tuyển người.
Ví dụ: "Dự án web mới, team dùng TypeScript, em chọn Playwright vì auto-wait giảm test chập chờn, chạy song song sẵn, có trace viewer để debug. Selenium vẫn hợp với dự án Java có sẵn nhiều script."
Hay sai: chọn vì "đang hot" mà không có lý do gắn với dự án.
07Core 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.
08Frontend 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
09Phâ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.
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 ở ISV Vietnam?
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