Hướng dẫn how does javascript event loop work? - vòng lặp sự kiện javascript hoạt động như thế nào?

JavaScript có mô hình thời gian chạy dựa trên vòng lặp sự kiện, chịu trách nhiệm thực thi mã, thu thập và xử lý các sự kiện và thực hiện các nhiệm vụ phụ hàng đợi. Mô hình này khá khác biệt so với các mô hình trong các ngôn ngữ khác như C và Java.event loop, which is responsible for executing the code, collecting and processing events, and executing queued sub-tasks. This model is quite different from models in other languages like C and Java.

Khái niệm thời gian chạy

Các phần sau đây giải thích một mô hình lý thuyết. Động cơ JavaScript hiện đại thực hiện và tối ưu hóa mạnh mẽ các ngữ nghĩa được mô tả.

Đại diện trực quan

Hướng dẫn how does javascript event loop work? - vòng lặp sự kiện javascript hoạt động như thế nào?

Cây rơm

Các cuộc gọi chức năng tạo thành một chồng khung.

function foo(b) {
  const a = 10;
  return a + b + 11;
}

function bar(x) {
  const y = 3;
  return foo(x * y);
}

const baz = bar(7); // assigns 42 to baz

Thứ tự hoạt động:

  1. Khi gọi bar, khung đầu tiên được tạo có chứa các tham chiếu đến các đối số và biến cục bộ của ____ 4.
  2. Khi bar gọi foo, khung thứ hai được tạo và đẩy lên trên cái đầu tiên, chứa các tham chiếu đến các đối số và biến cục bộ của ____ 7.
  3. Khi foo trả về, phần tử khung trên cùng được bật ra khỏi ngăn xếp (chỉ để lại khung cuộc gọi của ____ 4).
  4. Khi bar trở lại, ngăn xếp trống.

Lưu ý rằng các đối số và biến cục bộ có thể tiếp tục tồn tại, vì chúng được lưu trữ bên ngoài ngăn xếp - vì vậy chúng có thể được truy cập bởi bất kỳ chức năng lồng nhau nào từ lâu sau khi hàm bên ngoài của chúng trở lại.

Đống

Các đối tượng được phân bổ trong một đống chỉ là một tên để biểu thị một vùng bộ nhớ lớn (chủ yếu là không cấu trúc).

Xếp hàng

Thời gian chạy JavaScript sử dụng hàng đợi tin nhắn, đây là danh sách các tin nhắn được xử lý. Mỗi tin nhắn có một chức năng liên quan được gọi để xử lý tin nhắn.

Tại một số thời điểm trong vòng lặp sự kiện, thời gian chạy bắt đầu xử lý các tin nhắn trên hàng đợi, bắt đầu với cái cũ nhất. Để làm như vậy, thông báo được xóa khỏi hàng đợi và chức năng tương ứng của nó được gọi với thông báo dưới dạng tham số đầu vào. Như mọi khi, gọi một hàm tạo ra một khung ngăn xếp mới cho việc sử dụng chức năng đó.

Việc xử lý các chức năng tiếp tục cho đến khi ngăn xếp một lần nữa trống. Sau đó, vòng lặp sự kiện sẽ xử lý thông báo tiếp theo trong hàng đợi (nếu có một).

Vòng lặp sự kiện

Vòng lặp sự kiện có tên của nó vì cách nó thường được thực hiện, thường giống với:event loop got its name because of how it's usually implemented, which usually resembles:

while (queue.waitForMessage()) {
  queue.processNextMessage();
}

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
2 chờ đồng bộ cho một tin nhắn đến (nếu một người chưa có sẵn và chờ được xử lý).

"Run-to-completion"

Mỗi tin nhắn được xử lý hoàn toàn trước khi bất kỳ tin nhắn nào khác được xử lý.

Điều này cung cấp một số thuộc tính tốt đẹp khi lý luận về chương trình của bạn, bao gồm cả thực tế là bất cứ khi nào một hàm chạy, nó không thể được ưu tiên và sẽ chạy hoàn toàn trước khi bất kỳ mã nào khác chạy (và có thể sửa đổi dữ liệu mà chức năng thao túng). Điều này khác với C, ví dụ, nếu một hàm chạy trong một luồng, nó có thể bị dừng tại bất kỳ điểm nào bởi hệ thống thời gian chạy để chạy một số mã khác trong một luồng khác.

Một nhược điểm của mô hình này là nếu một thông báo mất quá nhiều thời gian để hoàn thành, ứng dụng web không thể xử lý các tương tác của người dùng như nhấp hoặc cuộn. Trình duyệt giảm thiểu điều này với hộp thoại "A Script mất quá nhiều thời gian để chạy". Một thực tế tốt để làm theo là thực hiện xử lý tin nhắn ngắn và nếu có thể cắt giảm một tin nhắn thành một số tin nhắn.

Thêm tin nhắn

Trong các trình duyệt web, tin nhắn được thêm vào bất cứ lúc nào một sự kiện xảy ra và có một trình nghe sự kiện được đính kèm với nó. Nếu không có người nghe, sự kiện bị mất. Vì vậy, một cú nhấp chuột vào một phần tử với một trình xử lý sự kiện nhấp vào sẽ thêm một thông báo - tương tự như vậy với bất kỳ sự kiện nào khác.

Hàm

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
3 được gọi với 2 đối số: một thông báo để thêm vào hàng đợi và giá trị thời gian (tùy chọn; mặc định là
while (queue.waitForMessage()) {
  queue.processNextMessage();
}
4). Giá trị thời gian biểu thị độ trễ (tối thiểu) sau đó tin nhắn sẽ được đẩy vào hàng đợi. Nếu không có thông báo nào khác trong hàng đợi và ngăn xếp trống, thông báo sẽ được xử lý ngay sau khi trì hoãn. Tuy nhiên, nếu có tin nhắn, tin nhắn
while (queue.waitForMessage()) {
  queue.processNextMessage();
}
3 sẽ phải chờ các tin nhắn khác được xử lý. Vì lý do này, đối số thứ hai cho thấy thời gian tối thiểu - không phải là thời gian được đảm bảo.

Dưới đây là một ví dụ chứng minh khái niệm này (

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
3 không chạy ngay sau khi bộ đếm thời gian của nó hết hạn):

const seconds = new Date().getTime() / 1000;

setTimeout(() => {
  // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  console.log(`Ran after ${new Date().getTime() / 1000 - seconds} seconds`);
}, 500)

while (true) {
  if (new Date().getTime() / 1000 - seconds >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}

Không chậm trễ

Không chậm trễ không có nghĩa là cuộc gọi lại sẽ bị sa thải sau khi 0 mili giây. Gọi

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
3 với độ trễ là
while (queue.waitForMessage()) {
  queue.processNextMessage();
}
4 (không) mili giây không thực thi chức năng gọi lại sau khoảng thời gian đã cho.

Việc thực hiện phụ thuộc vào số lượng các nhiệm vụ chờ đợi trong hàng đợi. Trong ví dụ dưới đây, thông báo

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
9 sẽ được ghi vào bảng điều khiển trước khi thông báo trong cuộc gọi lại được xử lý, vì độ trễ là thời gian tối thiểu cần thiết cho thời gian chạy để xử lý yêu cầu (không phải thời gian đảm bảo).

while (queue.waitForMessage()) {
  queue.processNextMessage();
}
3 cần chờ tất cả các mã cho các tin nhắn được xếp hàng hoàn thành mặc dù bạn đã chỉ định một giới hạn thời gian cụ thể cho
while (queue.waitForMessage()) {
  queue.processNextMessage();
}
3 của mình.

(() => {

  console.log('this is the start');

  setTimeout(() => {
    console.log('Callback 1: this is a msg from call back');
  }); // has a default time value of 0

  console.log('this is just a message');

  setTimeout(() => {
    console.log('Callback 2: this is a msg from call back');
  }, 0);

  console.log('this is the end');

})();

// "this is the start"
// "this is just a message"
// "this is the end"
// "Callback 1: this is a msg from call back"
// "Callback 2: this is a msg from call back"

Một số thời gian giao tiếp cùng nhau

Một nhân viên web hoặc một bộ phận có nguồn gốc chéo

const seconds = new Date().getTime() / 1000;

setTimeout(() => {
  // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  console.log(`Ran after ${new Date().getTime() / 1000 - seconds} seconds`);
}, 500)

while (true) {
  if (new Date().getTime() / 1000 - seconds >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}
2 có hàng xếp hàng, heap và tin nhắn riêng. Hai Runtimes riêng biệt chỉ có thể giao tiếp thông qua việc gửi tin nhắn thông qua phương thức
const seconds = new Date().getTime() / 1000;

setTimeout(() => {
  // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  console.log(`Ran after ${new Date().getTime() / 1000 - seconds} seconds`);
}, 500)

while (true) {
  if (new Date().getTime() / 1000 - seconds >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}
3. Phương thức này thêm một thông báo cho thời gian chạy khác nếu phương pháp sau lắng nghe các sự kiện
const seconds = new Date().getTime() / 1000;

setTimeout(() => {
  // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  console.log(`Ran after ${new Date().getTime() / 1000 - seconds} seconds`);
}, 500)

while (true) {
  if (new Date().getTime() / 1000 - seconds >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}
4.

Không bao giờ chặn

Một thuộc tính rất thú vị của mô hình vòng lặp sự kiện là JavaScript, không giống như nhiều ngôn ngữ khác, không bao giờ khối. Xử lý I/O thường được thực hiện thông qua các sự kiện và cuộc gọi lại, vì vậy khi ứng dụng đang chờ truy vấn IndexedDB để trả về hoặc yêu cầu XHR để trả về, nó vẫn có thể xử lý những thứ khác như đầu vào của người dùng.

Các ngoại lệ di sản tồn tại như

const seconds = new Date().getTime() / 1000;

setTimeout(() => {
  // prints out "2", meaning that the callback is not called immediately after 500 milliseconds.
  console.log(`Ran after ${new Date().getTime() / 1000 - seconds} seconds`);
}, 500)

while (true) {
  if (new Date().getTime() / 1000 - seconds >= 2) {
    console.log("Good, looped for 2 seconds");
    break;
  }
}
5 hoặc XHR đồng bộ, nhưng nó được coi là thực hành tốt để tránh chúng. Coi chừng: Các ngoại lệ cho ngoại lệ tồn tại (nhưng thường là các lỗi thực hiện, thay vì bất cứ điều gì khác).

Xem thêm

Vòng lặp sự kiện là gì và nó hoạt động như thế nào trong SetTimeout?

Vòng lặp sự kiện là những gì cho phép Node.js thực hiện các hoạt động I/O không chặn-mặc dù thực tế là JavaScript là một luồng đơn-bằng cách giảm tải các hoạt động cho nhân hệ thống bất cứ khi nào có thể. Vì hầu hết các hạt nhân hiện đại là nhiều luồng, chúng có thể xử lý nhiều hoạt động thực thi trong nền.allows Node. js to perform non-blocking I/O operations — despite the fact that JavaScript is single-threaded — by offloading operations to the system kernel whenever possible. Since most modern kernels are multi-threaded, they can handle multiple operations executing in the background.

Vòng lặp sự kiện trong JS là gì?

Công việc của vòng lặp sự kiện là nhìn vào ngăn xếp và nhìn vào hàng đợi nhiệm vụ. Nếu ngăn xếp trống, nó sẽ mất thứ đầu tiên trên hàng đợi và đẩy nó vào ngăn xếp có hiệu quả chạy nó.. If the stack is empty it takes the first thing on the queue and pushes it on to the stack which effectively run it.

Vòng lặp sự kiện trong các câu hỏi phỏng vấn JavaScript là gì?

Vòng lặp sự kiện là một cơ chế cho phép JavaScript thực hiện các hoạt động không chặn.Khi một nhiệm vụ không đồng bộ được bắt đầu, vòng lặp sự kiện sẽ bắt đầu chạy.Sau khi hoàn thành nhiệm vụ, vòng lặp sự kiện sẽ một lần nữa kiểm tra bất kỳ nhiệm vụ nào khác cần được thực hiện.a mechanism that allows JavaScript to perform non-blocking operations. When an asynchronous task is started, the event loop will start running. Once the task is completed, the event loop will again check for any other tasks that need to be performed.

Làm thế nào để vòng lặp sự kiện hoạt động trong nút js?

Vòng lặp sự kiện là một vòng lặp vô tận, chờ đợi các nhiệm vụ, thực hiện chúng và sau đó ngủ cho đến khi nhận được nhiều nhiệm vụ hơn.Vòng lặp sự kiện chỉ thực hiện các tác vụ từ hàng đợi sự kiện khi ngăn xếp cuộc gọi trống tức là không có nhiệm vụ đang diễn ra.Vòng lặp sự kiện cho phép chúng tôi sử dụng các cuộc gọi lại và lời hứa.waits for tasks, executes them and then sleeps until it receives more tasks. The event loop executes tasks from the event queue only when the call stack is empty i.e. there is no ongoing task. The event loop allows us to use callbacks and promises.