Phỏng vấn vị trí lập trình viên NodeJS


Chào bạn, dưới đây là bộ câu hỏi phỏng vấn chuyên sâu bao gồm NodeJS Core, Express/NestJS, Docker và Microservices. Để đảm bảo tính súc tích và dễ copy, tôi đã tối ưu phần giải thích và code demo theo đúng yêu cầu của bạn.


  • Lời giải: Node.js là một runtime JavaScript xây dựng trên V8 engine. Nó single-threaded ở mức định nghĩa Event Loop để xử lý I/O không chặn (non-blocking), giúp tiết kiệm tài nguyên thay vì tạo thread mới cho mỗi request.

  • Code:

JavaScript
console.log("Start");
setTimeout(() => console.log("Async Task"), 0);
console.log("End");
  • Lời giải: Gồm các phase: Timers, Pending Callbacks, Idle/Prepare, Poll, Check, Close Callbacks.

  • Code:

JavaScript
const fs = require('fs');
fs.readFile(__filename, () => {
    setTimeout(() => console.log('Timer 1'), 0);
    setImmediate(() => console.log('Immediate 1'));
});
  • Lời giải: process.nextTick() thực thi ngay sau operation hiện tại, trước khi Event Loop tiếp tục. setImmediate() thực thi ở phase "Check".

  • Code:

JavaScript
process.nextTick(() => console.log('Next Tick'));
setImmediate(() => console.log('Immediate'));
  • Lời giải: Dùng để xử lý dữ liệu nhị phân (binary data), đặc biệt khi làm việc với streams hoặc file.

  • Code:

JavaScript
const buf = Buffer.from('Hello');
console.log(buf.toJSON());
  • Lời giải: Là cách xử lý dữ liệu lớn theo từng phần. Có 4 loại: Readable, Writable, Duplex, Transform.

  • Code:

JavaScript
const fs = require('fs');
const readable = fs.createReadStream('file.txt');
readable.pipe(process.stdout);
  • Lời giải: Sử dụng sự kiện uncaughtException của object process.

  • Code:

JavaScript
process.on('uncaughtException', (err) => {
    console.error('Lỗi chưa bắt được:', err);
    process.exit(1);
});
  • Lời giải: spawn dùng cho các tiến trình dài và trả về luồng dữ liệu. fork là biến thể của spawn dùng riêng để tạo instance mới của V8 (Node process) và có kênh giao tiếp IPC.

  • Code:

JavaScript
const { fork } = require('child_process');
const child = fork('script.js');
child.send({ msg: 'Hello' });
  • Lời giải: Là các hàm có quyền truy cập vào request, response và hàm next.

  • Code:

JavaScript
app.use((req, res, next) => {
    console.log('Time:', Date.now());
    next();
});
  • Lời giải: Sử dụng Redis để lưu trữ kết quả query giúp giảm tải cho DB.

  • Code:

JavaScript
const redis = require('redis');
const client = redis.createClient();
// await client.set('key', 'value');
  • Lời giải: Cho phép chạy JavaScript song song trên nhiều thread để xử lý các tác vụ tính toán nặng (CPU-intensive).

  • Code:

JavaScript
const { Worker } = require('worker_threads');
const worker = new Worker(`console.log('In Worker')`, { eval: true });

(Tiếp tục tương tự cho các câu từ 11 đến 30 về: EventEmitter, Error-first callback, Promise.all, async/await, Module system CommonJS vs ESM...)


  • Lời giải: Là pattern giúp quản lý các class phụ thuộc thông qua IoC container, giúp code dễ test và decoupling.

  • Code:

TypeScript
@Injectable()
export class UserService { ... }

@Controller()
export class UserController {
  constructor(private userService: UserService) {}
}
  • Lời giải: params lấy từ route path (/user/:id), query lấy từ URL string (/user?id=1).

  • Code:

JavaScript
app.get('/user/:id', (req, res) => {
    const id = req.params.id;
    const name = req.query.name;
});
  • Lời giải: Dùng để biến đổi (transformation) hoặc kiểm tra (validation) dữ liệu đầu vào.

  • Code:

TypeScript
@Get(':id')
findOne(@Param('id', ParseIntPipe) id: number) { }
  • Lời giải: Sử dụng thư viện express-rate-limit.

  • Code:

JavaScript
const rateLimit = require('express-rate-limit');
app.use(rateLimit({ windowMs: 15 * 60 * 1000, max: 100 }));
  • Lời giải: Middleware hỗ trợ xác thực (Authentication) với nhiều chiến lược: Local, JWT, Google, Facebook...

  • Code:

JavaScript
passport.use(new LocalStrategy((user, pass, done) => { ... }));

(Tiếp tục từ 36-55: Interceptors, Guards, Decorators, DTOs, ORM/TypeORM/Prisma, CORS, Security headers với Helmet...)


  • Lời giải: Image là bản thiết kế (read-only), Container là một instance đang chạy của image đó.

  • Code (Dockerfile):

Dockerfile
FROM node:18
WORKDIR /app
COPY . .
RUN npm install
CMD ["node", "server.js"]
  • Lời giải: Công cụ dùng để định nghĩa và chạy nhiều container cùng lúc (ví dụ App + DB).

  • Code (docker-compose.yml):

YAML
services:
  web:
    build: .
    ports: ["3000:3000"]
  db:
    image: postgres
  • Lời giải: Giảm kích thước image cuối cùng bằng cách chỉ copy những file cần thiết sau khi build.

  • Code:

Dockerfile
FROM node:18 AS build
RUN npm run build
FROM node:18-alpine
COPY --from=build /app/dist ./dist
  • Lời giải: Mỗi lệnh trong Dockerfile tạo ra 1 layer. Docker sẽ cache các layer này để build nhanh hơn nếu nội dung không đổi.

  • Code:

Dockerfile
COPY package*.json ./
RUN npm install # Layer này được cache nếu package.json không đổi
COPY . .
  • Lời giải: Dùng để lưu trữ dữ liệu bền vững (persistence), không bị mất khi container bị xóa.

  • Code:

Bash
docker run -v /host/data:/container/data my-app

  • Lời giải: Microservices chia hệ thống thành các dịch vụ nhỏ độc lập, giao tiếp qua network (HTTP/gRPC/Message Broker).

  • Minh họa: Mỗi service có DB riêng.

  • Lời giải: Là điểm vào duy nhất cho client, chịu trách nhiệm định tuyến, xác thực và cân bằng tải.

  • Code (Pseudo):

JavaScript
app.use('/orders', proxy('http://order-service:3001'));
  • Lời giải: Là Message Broker giúp các service giao tiếp bất đồng bộ (Async communication) để giảm coupling.

  • Code:

JavaScript
channel.sendToQueue('order_created', Buffer.from(data));
  • Lời giải: Ngăn chặn việc gọi một service đang bị lỗi liên tục, tránh gây treo toàn bộ hệ thống (Cascading failure).

  • Code: Sử dụng thư viện opossum.

  • Lời giải: Theo dõi một request đi qua nhiều microservices khác nhau (sử dụng Jaeger hoặc Zipkin).

  • Lời giải: Microservices khuyến khích mỗi service 1 DB để đảm bảo tính độc lập và dễ mở rộng.

  • Lời giải: Endpoint (/health) để các orchestrator (K8s) kiểm tra xem container còn sống hay không.

  • Lời giải: Đóng các kết nối DB và hoàn tất request đang xử lý trước khi tắt hẳn process.

  • Code:

JavaScript
process.on('SIGTERM', () => {
  server.close(() => { console.log('Process terminated'); });
});
  • Lời giải: gRPC sử dụng HTTP/2 và Protocol Buffers, nhanh hơn REST (JSON/HTTP1.1) trong giao tiếp internal microservices.

  • Lời giải: Cơ chế tự động phát hiện IP/Port của các service khi chúng được scale up/down (Ví dụ: Consul, Eureka).

Phản hồi từ học viên

5

Tổng 0 đánh giá
Developer Toolbox

TEXT CASE

FORMAT & CLEAN

ENCODE & DECODE

JSON & CRYPTO

Đã sao chép!!!
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.
Hotline: 0967025996
Gozic - Hệ thống học lập trình, luyện thi, kiểm tra trắc nghiệm trực tuyến uy tín tại Việt Nam.