setTimeout(functionA, 1000) Có phải sau 1 giây, functionA sẽ được thực hiện?

Để trả lời cho câu hỏi trên, cùng thực hiện 2 ví dụ để xem kết quả là gì nhé!

Ví dụ 1:

console.log(1);
setTimeout(function () {
  console.log(3);
}, 1000);
console.log(2);

Trong ví dụ trên, thứ tự hiển thị sẽ là 1, 2 rồi đến 3, và số 3 xuất hiện sau 1 giây.

1
2
3 //will appear after 1s

OK chuẩn rồi, tiếp tục đến ví dụ thứ 2.

Ví dụ 2:

console.log(1);
setTimeout(function () {
  console.log(3);
}, 1000);
for (let i = 0; i < 1e+25; i++) {
  //do nothing
}

Kết quả khi chạy là sau 1 giây, số 3 sẽ không xuất hiện. Tại sao vậy, theo lý thuyết nó phải xuất hiện chứ? Cùng tìm hiểu tại sao lại thế nhé.

Javascript chỉ thực thi đơn luồng, có nghĩa là tại mỗi thời điểm chỉ có một tác vụ được thực thi. Do đó, function setTimeout ở trên chỉ thực hiện khi kết thúc vòng lặp, và vòng lặp này chạy tới 1e+25 nên thời gian để chạy là rất lâu. Vì vậy, mặc dù thời gian mong muốn là 1 giây sẽ in ra số 3, nhưng thực tế phải đợi cho tới khi nào vòng lặp thực hiện xong. Điều đó có nghĩa rằng bạn set 1000ms vào setTimeout nhưng không phải sau đúng 1000ms là function sẽ được thực thi, ngay cả với trường hợp 0ms, function cũng không chắc chắn được thực thi ngay lúc đó.

Thử xem lại định nghĩa về setTimeout là gì tại đây nhé.

delay | Optional

The time, in milliseconds (thousandths of a second), the timer should wait before the specified function or code is executed. If this parameter is omitted, a value of 0 is used, meaning execute "immediately", or more accurately, the next event cycle. Note that in either case, the actual delay may be longer than intended.


Nếu tham số này không được truyền, thì giá trị 0 sẽ được sử dụng, có nghĩa là "ngay lập tức", hoặc chính xác hơn, trong chu kì sự kiện tiếp theo . Lưu ý rằng thời gian thực tế có thể lâu hơn so với dự kiến.

OK vế đầu là những cái cơ bản chúng ta biết, còn cái "hoặc" phía sau có nghĩa là gì, chu kì sự kiện tiếp theo là gì?

Đây là cơ chế hoạt động của Event loop.

Event loop chỉ có duy nhất 1 nhiệm vụ, theo dõi call stack và những tác vụ nào cần thực hiện trong callback queue. Chỉ khi nào call stack trống, thì nó sẽ lấy tác vụ đầu tiên trong callback queue ra và đẩy vào call stack.

Để minh họa đơn giản cho ví dụ 2, mình nhóm từng bước vòng lặp lại là loop_at_i=0, ... loop_at_i=X (với 0 < X < (1e+25)-1), loop_at_i=(1e+25)-1.

  1. Call stack rỗng, chưa có gì được thực hiện

  1. console.log(1) được đẩy vào stack

  1. console.log(1) được thực hiện

  1. console.log(1) bị xóa khỏi stack

  1. setTimeout được đẩy vào stack

  1. setTimeout được thực hiện

  1. setTimeout bị xóa khỏi stack

  1. loop_at_i=0 được đẩy vào stack

  1. loop_at_i=0 được thực hiện (Không có gì thay đổi)
  2. loop_at_i=0 bị xóa khỏi stack

  1. Sau 1s, cb được đẩy vào callback queue

  1. loop_at_i=X được đẩy vào stack

  1. loop_at_i=X được thực hiện (Không có gì thay đổi)
  2. loop_at_i=X bị xóa khỏi stack

  1. loop_at_i=(1e+25)-1 được đẩy vào stack

  1. loop_at_i=(1e+25)-1 được thực hiện (Không có gì thay đổi)
  2. loop_at_i=(1e+25)-1 bị xóa khỏi stack

  1. stack trống, event loop đẩy cb vào stack

  1. cb được thực hiện, đẩy console.log(3) vào stack

  1. console.log(3) được thực hiện

  1. console.log(3) bị xóa khỏi stack

  1. cb bị xóa khỏi stack


Vậy trả lời thế nào là đúng cho câu hỏi ở tiêu đề, đó là functionA sẽ được thực hiện sau ít nhất 1 giây.

Tài liệu tham khảo:

https://medium.com/javascript-in-plain-english/better-understanding-of-timers-in-javascript-settimeout-vs-requestanimationframe-bf7f99b9ff9b

https://dev.to/khaosdoctor/node-js-under-the-hood-3-deep-dive-into-the-event-loop-135d


All Rights Reserved