Việc làm

18/09 · Cần Thơ · Tại văn phòng

[Cần Thơ] Fresher PHP (Good English communication)

CÔNG TY TNHH NEXTEDGE · Fullstack Developer

Xem mô tả & ứng tuyển trên ITviecMô tả công việc, lương và ứng tuyển nằm ở ITviec.

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). 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.

  1. 01this trong JavaScript được xác định thế nào? Arrow function khác function thường ở điểm nào?JavaScript & TypeScript · Junior

    Gợi ý trả lời

    Với function thường, this phụ thuộc vào cách gọi, không phải nơi định nghĩa:

    • obj.method(): this là obj.
    • Gọi hàm trơn fn(): undefined trong strict mode (module và class luôn là strict).
    • new Fn(): object mới được tạo.
    • fn.call(x), fn.apply(x), fn.bind(x): this là x.

    Arrow function không có this riêng; nó lấy this của phạm vi bao ngoài. Arrow function cũng không có arguments và không dùng được với new.

    const btn = { label: "OK", click() { setTimeout(() => console.log(this.label)); } };
    

    Hay sai: truyền obj.method làm callback (setTimeout(obj.method)) rồi mất this. Cách sửa: bind, hoặc bọc trong arrow function.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  2. 02Event 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

    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.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  3. 03So sánh Promise.all, Promise.allSettled, Promise.race và Promise.any. Xử lý lỗi với async/await thế nào?JavaScript & TypeScript

    Gợi ý trả lời

    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: await lầ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ọi Promise.all vớ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.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  4. 04Composite index (index nhiều cột) hoạt động ra sao? Thứ tự cột có quan trọng không?SQL & Database

    Gợi ý trả lời

    Có. Composite index sắp xếp theo cột đầu, rồi đến cột thứ hai trong cùng giá trị cột đầu, v.v. Vì vậy nó chỉ dùng hiệu quả khi query dùng các cột từ trái sang (leftmost prefix).

    Với INDEX (status, created_at):

    • WHERE status = 'paid' AND created_at > ...: dùng tốt.
    • WHERE status = 'paid' ORDER BY created_at DESC: dùng cho cả lọc lẫn sắp xếp.
    • WHERE created_at > ... (không có status): thường không dùng được.

    Nguyên tắc chọn thứ tự: cột so sánh bằng (=) đặt trước, cột so sánh khoảng hoặc sắp xếp đặt sau. Nếu index chứa đủ mọi cột query cần (covering index) thì DB không phải đọc lại bảng.

    Hay sai: tạo riêng index cho từng cột rồi nghĩ rằng chúng sẽ kết hợp hiệu quả như một composite index.

    Ôn thêm câu hỏi SQL & Database →
  5. 05Các isolation level là gì? Dirty read, non-repeatable read, phantom read khác nhau thế nào?SQL & Database

    Gợi ý trả lời

    Isolation level quyết định một transaction thấy được bao nhiêu thay đổi của transaction khác; mức càng cao càng an toàn nhưng càng dễ tranh chấp.

    • Dirty read: đọc dữ liệu transaction khác chưa commit.
    • Non-repeatable read: đọc lại cùng một dòng thấy giá trị đã đổi.
    • Phantom read: chạy lại cùng điều kiện thấy thêm hoặc mất dòng.

    Bốn mức chuẩn: Read Uncommitted, Read Committed, Repeatable Read, Serializable. Mặc định của PostgreSQL, SQL Server, Oracle là Read Committed; MySQL InnoDB là Repeatable Read.

    Thực tế các DB dùng MVCC nên hành vi có khác lý thuyết: Repeatable Read của PostgreSQL dùng snapshot nên không gặp phantom, còn InnoDB dùng gap lock cho câu đọc có khoá.

    Người phỏng vấn muốn nghe: bạn biết DB mình dùng mặc định ở mức nào và đã từng xử lý lost update, vd. bằng SELECT ... FOR UPDATE hoặc optimistic locking.

    Ôn thêm câu hỏi SQL & Database →
  6. 06Trong TypeScript, interface và type khác nhau thế nào? Phân biệt any, unknown và never.JavaScript & TypeScript

    Gợi ý trả lời

    Cả hai đều mô tả hình dạng object và phần lớn trường hợp dùng thay nhau được.

    • interface có thể gộp khai báo (declaration merging) và extends; hợp để mô tả object, API công khai.
    • type mô 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 trong switch.
    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).

    Ôn thêm câu hỏi JavaScript & TypeScript →
  7. 07Debounce 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

    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.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  8. 08Phân biệt var, let và const. Hoisting và temporal dead zone là gì?JavaScript & TypeScript · Junior

    Gợi ý trả lời

    var có phạm vi hàm, còn let/const có phạm vi block ({}). const khô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/const cũng được hoist nhưng chưa khởi tạo. Truy cập trước dòng khai báo ném ReferenceError; 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ùng let, và gần như không dùng var trong code mới.

    Ôn thêm câu hỏi JavaScript & TypeScript →
  9. 09Một API chạy chậm, nghi do query. Bạn điều tra và tối ưu thế nào?SQL & Database

    Gợi ý trả lời

    Đo trước rồi mới sửa: tìm đúng query chậm, đọc execution plan, rồi chỉnh index hoặc cách viết query.

    1. Bật slow query log (MySQL) hoặc pg_stat_statements (PostgreSQL) để biết query nào tốn thời gian nhất.
    2. Chạy EXPLAIN (PostgreSQL nên dùng EXPLAIN (ANALYZE, BUFFERS)) xem có full scan, ước lượng số dòng lệch nhiều so với thực tế, sort trên đĩa không.
    3. Sửa theo nguyên nhân: thêm hoặc đổi composite index, bỏ hàm bọc cột, chỉ SELECT cột cần, phân trang bằng keyset thay cho OFFSET lớn.
    4. Kiểm tra phía ứng dụng: lỗi N+1 query, thiếu connection pool, lock chờ lâu.
    5. Cập nhật thống kê (ANALYZE) nếu planner ước lượng sai.

    Người phỏng vấn muốn nghe: quy trình có số liệu trước/sau, không phải đoán rồi thêm index bừa.

    Ôn thêm câu hỏi SQL & Database →
  10. 10Bạn làm việc thế nào khi áp lực cao hoặc deadline gấp?Câu hỏi hành vi & văn hoá

    Gợi ý trả lời

    Cho thấy bạn có cách làm cụ thể, không chỉ nói "em chịu được áp lực".

    • Chia nhỏ việc, ưu tiên phần quan trọng nhất cho mục tiêu.
    • Báo sớm cho lead/PM nếu thấy không kịp, đề xuất cắt phạm vi hoặc xin hỗ trợ.
    • Giữ chất lượng ở phần cốt lõi; ghi lại nợ kỹ thuật để xử lý sau.
    • Giữ bình tĩnh, giao tiếp ngắn gọn, rõ ràng với team.

    Câu mẫu theo STAR: "Trước buổi demo cho khách, team phát hiện lỗi tích hợp chỉ còn hai ngày. Em liệt kê các phần bị ảnh hưởng, cùng PM chọn luồng nào bắt buộc phải chạy cho demo, phần còn lại hẹn bàn giao tuần sau. Demo diễn ra suôn sẻ và khách đồng ý với lịch mới."

    Hay sai: khoe thức trắng nhiều đêm. Người phỏng vấn muốn thấy bạn quản lý được áp lực, không chỉ chịu đựng.

    Ôn thêm câu hỏi Câu hỏi hành vi & văn hoá →

Bạn đã phỏng vấn ở CÔNG TY TNHH NEXTEDGE?

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