⚙️ XỬ LÝ BẤT ĐỒNG BỘ – CẤP ĐỘ THỰC CHIẾN

Chương 1: Hiểu Sâu JavaScript Runtime & Bất Đồng Bộ

1.1. JavaScript Runtime Environment

JavaScript ban đầu được thiết kế để chạy trong trình duyệt, nhưng với sự ra đời của Node.js, ngôn ngữ này đã có thể vận hành ở backend. Dù chạy trong browser hay server, JavaScript luôn hoạt động trong một "runtime environment" với nhiều thành phần quan trọng:

1.1.1. Call Stack

Là ngăn xếp (stack) để theo dõi hàm nào đang được thực thi. Mỗi khi một hàm được gọi, nó được đẩy vào stack; khi kết thúc, nó bị lấy ra.

1.1.2. Heap

Là vùng nhớ cho Object và tham chiếu, được sử dụng cho các giá trị không phải primitive.

1.1.3. Web APIs / C++ Bindings

Chỉ có trong browser/Node. Browser cung cấp Web API (như setTimeout, DOM, fetch), còn Node.js cung cấp các binding như fs, http, net.

1.1.4. Callback Queue / Task Queue

Queue chờ các hàm async như setTimeout, setInterval, I/O v.v. Macrotask Queue và Microtask Queue là 2 loại chính.

1.1.5. Event Loop

Trái tim của JavaScript: luân phiên đẩy task từ queue vào call stack khi stack rỗng.

1.2. Event Loop trong thực tiễn

console.log("A");
setTimeout(() => console.log("B"), 0);
Promise.resolve().then(() => console.log("C"));
console.log("D");

Kết Quả:

A
D
C
B

Giải thích:

  • AD: chạy ngay trong call stack

  • Promise.then: đưa vào Microtask Queue, chạy sau khi call stack rỗng

  • setTimeout: vào Macrotask Queue, chạy sau microtask

1.3. Callback

Định nghĩa:

Là một hàm được truyền làm đối số và được gọi sau khi hoàn thành tác vụ.

function fetchData(callback) {
  setTimeout(() => callback("Done"), 1000);
}

Nhược điểm:

  • Callback hell

  • Khó debug

  • Tổ chức logic phức tạp

1.4. Promise

Định nghĩa:

Là một object đại diện cho kết quả bất đồng bộ tương lai

const promise = new Promise((resolve, reject) => {
  if (success) resolve(data);
  else reject(error);
});

Trạng thái:

  • Pending

  • Fulfilled

  • Rejected

1.5. Promise Chaining

fetchUser()
  .then((user) => fetchProfile(user.id))
  .then((profile) => console.log(profile))
  .catch(console.error);

Lời ích:

  • Code dễ đọc

  • Tách rời xử lý logic và lỗi

1.6. Async / Await

async function loadProfile() {
  try {
    const user = await fetchUser();
    const profile = await fetchProfile(user.id);
    console.log(profile);
  } catch (err) {
    console.error(err);
  }
}

Lời ích:

  • Code đọc tuỳ như đồng bộ

  • Dễ debug

1.7. Promise.all, allSettled, race

const [res1, res2] = await Promise.all([api1(), api2()]);
  • Promise.all: chờ tất cả resolve, fail 1 là reject toàn bộ

  • Promise.allSettled: resolve tất cả, báo trạng thái

  • Promise.race: resolve/reject đầu tiên

1.8. Debounce & Throttle

Debounce:

Chỉ chạy sau một khoảng delay nếu ngưng gọi

function debounce(fn, delay) {
  let timer;
  return (...args) => {
    clearTimeout(timer);
    timer = setTimeout(() => fn.apply(this, args), delay);
  };
}

Throttle:

Giới hạn tần suất gọi trong khoảng thời gian

function throttle(fn, limit) {
  let lastCall = 0;
  return (...args) => {
    const now = Date.now();
    if (now - lastCall >= limit) {
      lastCall = now;
      fn.apply(this, args);
    }
  };
}

1.9. Tổng Kết

Khái niệm
Vai trò

Runtime

Nền tảng vận hành cho JS

Event Loop

Cơ chế điều phối bất đồng bộ

Callback/Promise

Cách xử lý async logic

Async/Await

Code async dễ hiểu, gắn với Promise

Debounce/Throttle

Tối ưu hiệu suất trong UI

Promise.all

Chờ nhiều promise song song, rất quan trọng trong API calls

Trong những hệ thống lớn, việc nắm vững những kiến thức trên giúp senior developer viết code bền vững, scale được và xử lý tình huống async phức tạp một cách chính xác.

Last updated