0

Tìm hiểu về V8 Engine trong Chrome và Node.js

Mở đầu

Chrome hay Node.js được gọi là Javascript Runtime Enviroment.

V8 Engine: Các thành phần chính và chức năng

  • V8 Engine có các thành phần cơ bản sau:
Sơ đồ về các thành phần của V8 Engine và cơ chế hoạt động

1. Parser (Bộ phân tích cú pháp)

  • Chuyển mã JavaScript từ chuỗi văn bản thành cấu trúc dữ liệu mà V8 engine có thể hiểu.
  • Quá trình này gồm 2 bước:
Bước Chi tiết thực thi
1. Lexical Analysis (Tokenizer/Lexer) Chia mã nguồn thành các token (như từ khóa, toán tử, biến...).
2. Syntax Analysis (Parser) Xây dựng AST (Abstract Syntax Tree - Cây cú pháp trừu tượng) từ các token.
  • Một ví dụ:
js

let x = 4 + 5;
  • AST sau khi đã được chuyển đổi từ mã nguồn ở trên:
VariableDeclaration
 ├── Identifier (x)
 ├── Assignment (=)
 ├── BinaryExpression (+)
       ├── Number (4)
       ├── Number (5)

2. Ignition Interpreter (Trình thông dịch)

  • Đọc AST và chuyển đổi thành Bytecode (dạng mã trung gian tối ưu) sau đó thực thi các đoạn mã Bytecode này.

3. TurboFan (JIT Compiler)

  • Nếu một đoạn mã chạy nhiều lần, V8 xác định nó là mã quan trọng, cần được tối ưu hóa.
  • TurboFan sẽ biên dịch các đoạn mã Bytecode quan trọng này thành mã máy tối ưu hóa để tăng tốc thực thi.
  • Một số ví dụ về cách TurboFan chuyển đổi thành mã máy tối ưu hóa:

3.1. Nhúng trực tiếp các hàm nhỏ (Inlining)

  • Nếu một hàm được gọi nhiều lần, TurboFan có thể nhúng toàn bộ mã của hàm vào nơi gọi thay vì thực hiện một lệnh gọi hàm tốn thời gian.
js

function add(a, b) {
    return a + b;
}

function calc(x, y) {
    return add(x, y) * 2;
}
  • Trước tối ưu hóa: calc(x, y) phải gọi add(x, y), gây quá tải (overhead).
  • Sau tối ưu hóa: TurboFan sẽ thay add(x, y) bằng x + y, tránh gọi hàm.

3.2. Loại bỏ mã không cần thiết (Dead Code Elimination)

  • Nếu một biến hoặc đoạn mã không ảnh hưởng đến kết quả, TurboFan sẽ loại bỏ nó.
js

function test() {
    let x = 10;
    let y = x + 5;
    return x;  // y không được sử dụng => loại bỏ y khi biên dịch
}
  • TurboFan sẽ loại bỏ y, giúp mã chạy nhanh hơn.

3.3. Loop Unrolling (Tối ưu vòng lặp)

  • Nếu vòng lặp có số lần lặp nhỏ và cố định, TurboFan có thể triển khai vòng lặp thành các lệnh tuần tự để tránh kiểm tra điều kiện lặp nhiều lần.
js

for (let i = 0; i < 3; i++) {
    console.log(i);
}

Sau tối ưu hóa:

js

console.log(0);
console.log(1);
console.log(2);

4. Garbage Collector (Bộ thu gom rác)

  • Dọn dẹp bộ nhớ bằng cách xóa các đối tượng không còn được sử dụng.
  • V8 Engine dùng thuật toán Mark-and-Sweep:
Bước Thực thi
Mark (Đánh dấu) Xác định đối tượng nào vẫn đang được tham chiếu
Sweep (Dọn dẹp) Giải phóng bộ nhớ của đối tượng không còn tham chiếu

ví dụ:

js

function genarate() {
  let obj = { name: "Viblo" };
}
genarate(); // obj bị xóa khỏi bộ nhớ sau khi hàm genarate() kết thúc

5. Call Stack

  • Call Stack là một cấu trúc dữ liệu dùng để quản lý lời gọi hàm trong quá trình thực thi mã JavaScript.
  • Hoạt động theo nguyên tắc LIFO (Last In, First Out) - nghĩa là hàm nào vào sau thì sẽ được thực thi trước, sau đó hàm đã thực thi sẽ bị loại khỏi Stack.
  • Ví dụ:
js

function first() {
  console.log("First function");
}

function second() {
  first();
  console.log("Second function");
}

function third() {
  second();
  console.log("Third function");
}

third();
Cách Call Stack hoạt động
1. third() được đưa vào Call Stack.
2. second() được gọi trong third(), nên nó cũng được đẩy vào Stack.
3. first() được gọi trong second(), nên nó cũng được đẩy vào Stack.
4. console.log("First function") thực thi → "First function" in ra màn hình.
5. first() hoàn thành, bị loại khỏi Call Stack.
6. console.log("Second function") thực thi → "Second function" in ra.
7. second() hoàn thành, bị loại khỏi Call Stack.
8. console.log("Third function") thực thi → "Third function" in ra.
9. third() hoàn thành, bị loại khỏi Call Stack.

6. Heap Memory

  • Heap Memory là vùng nhớ dùng để lưu trữ dữ liệu động như: Object, Array, Function.
  • Giúp lưu trữ dữ liệu một cách lâu dài hơn.
js

let x = 1;           // Lưu trong Stack (giá trị nguyên thủy)
let obj = { a: 1 };   // Lưu trong Heap (đối tượng)

Kết luận

  • Qua bài viết, chúng ta đã tìm hiểu về V8 một Javascript Engine trong trình duyệt Chrome, Node.js.
  • Nắm rõ được các khái niệm tổng quan về cấu tạo của V8 Engine cũng như vai trò, chức năng của từng thành phần.
  • Từ giờ khi viết Javascript, các bạn sẽ cảm thấy tự tin và có một cách nhìn rõ ràng hơn về cách ngôn ngữ này được xử lý và thực thi 🥰.

All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí