setTimeout(functionA, 1000) Có phải sau 1 giây, functionA sẽ được thực hiện?
Bài đăng này đã không được cập nhật trong 4 năm
Để 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.
- Call stack rỗng, chưa có gì được thực hiện
console.log(1)
được đẩy vào stack
console.log(1)
được thực hiện
console.log(1)
bị xóa khỏi stack
setTimeout
được đẩy vào stack
setTimeout
được thực hiện
setTimeout
bị xóa khỏi stack
loop_at_i=0
được đẩy vào stack
loop_at_i=0
được thực hiện (Không có gì thay đổi)loop_at_i=0
bị xóa khỏi stack
- Sau 1s,
cb
được đẩy vào callback queue
loop_at_i=X
được đẩy vào stack
loop_at_i=X
được thực hiện (Không có gì thay đổi)loop_at_i=X
bị xóa khỏi stack
loop_at_i=(1e+25)-1
được đẩy vào stack
loop_at_i=(1e+25)-1
được thực hiện (Không có gì thay đổi)loop_at_i=(1e+25)-1
bị xóa khỏi stack
- stack trống, event loop đẩy
cb
vào stack
cb
được thực hiện, đẩyconsole.log(3)
vào stack
console.log(3)
được thực hiện
console.log(3)
bị xóa khỏi stack
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://dev.to/khaosdoctor/node-js-under-the-hood-3-deep-dive-into-the-event-loop-135d
All rights reserved