SetTimeout hoạt động như thế nào trong Node.JS?


112

Tôi đoán rằng một khi nó được thực thi, nó sẽ ở trên hàng đợi, nhưng trong hàng đợi liệu có đảm bảo rằng nó sẽ gọi chính xác sau X mili giây không? Hay các tác vụ nặng khác cao hơn trong hàng đợi sẽ làm chậm trễ nó?


14
Không có hệ điều hành không thời gian thực nào có thể đảm bảo độ chính xác nghiêm trọng. Tất cả mọi thứ trên hệ thống có thể (và sẽ) cản trở cơ chế hẹn giờ.
Pointy

Câu trả lời:


174

Ngữ nghĩa của setTimeout gần giống như trong trình duyệt web: đối số timeout là số mili giây tối thiểu để chờ trước khi thực thi, không phải là một đảm bảo. Hơn nữa, chuyển 0, không phải số hoặc số âm, sẽ khiến nó đợi một số ms tối thiểu. Trong Node, đây là 1ms, nhưng trong các trình duyệt, nó có thể lên tới 50ms.

Lý do cho điều này là JavaScript không có quyền ưu tiên của JavaScript. Hãy xem xét ví dụ này:

setTimeout(function () {
  console.log('boo')
}, 100)
var end = Date.now() + 5000
while (Date.now() < end) ;
console.log('imma let you finish but blocking the event loop is the best bug of all TIME')

Dòng chảy ở đây là:

  1. lập lịch thời gian chờ cho 100ms.
  2. đang chờ 5000ms.
  3. trở lại vòng lặp sự kiện. kiểm tra bộ hẹn giờ đang chờ xử lý và thực thi.

Nếu không đúng như vậy, thì bạn có thể có một bit JavaScript "làm gián đoạn" một bit khác. Chúng tôi sẽ phải thiết lập mutexes và semaphors và những thứ tương tự, để ngăn những đoạn mã như thế này cực kỳ khó để suy luận về:

var a = 100;
setTimeout(function () {
  a = 0;
}, 0);
var b = a; // 100 or 0?

Tính đơn luồng của quá trình thực thi JavaScript của Node giúp nó làm việc đơn giản hơn nhiều so với hầu hết các kiểu đồng thời khác. Tất nhiên, sự đánh đổi là có thể một phần của chương trình hoạt động kém có thể chặn toàn bộ bằng một vòng lặp vô hạn.

Đây có phải là một con quỷ tốt hơn để chiến đấu hơn là sự phức tạp của đòn phủ đầu? Mà phụ thuộc.


20
Bạn nhận được +1 cho console.logtin nhắn đặc biệt chính xác .
Vụ kiện của Fund Monica vào

Tôi thích cách bạn viết hoa TIME trong chuỗi của mình. Giải thích rất hay !!!
Alisson

43

Ý tưởng của không chặn là các lần lặp lại vòng lặp nhanh chóng. Vì vậy, để lặp lại cho mỗi lần đánh dấu nên mất một khoảng thời gian đủ ngắn để setTimeout sẽ chính xác trong phạm vi chính xác hợp lý (có thể giảm xuống dưới 100 ms hoặc lâu hơn).

Về lý thuyết, mặc dù bạn đúng. Nếu tôi viết một ứng dụng và chặn đánh dấu, thì setTimeouts sẽ bị trì hoãn. Vì vậy, để trả lời câu hỏi của bạn, ai có thể đảm bảo setTimeouts thực thi đúng thời gian? Bạn, bằng cách viết mã không chặn, có thể kiểm soát mức độ chính xác lên đến hầu hết mọi mức độ chính xác hợp lý.

Miễn là javascript là "đơn luồng" về mặt thực thi mã (không bao gồm web-worker và những thứ tương tự), điều đó sẽ luôn xảy ra. Bản chất đơn luồng là một sự đơn giản hóa rất lớn trong hầu hết các trường hợp, nhưng yêu cầu thành ngữ không chặn để thành công.

Hãy thử mã này trong trình duyệt hoặc trong nút của bạn, và bạn sẽ thấy rằng không có gì đảm bảo về độ chính xác, ngược lại, setTimeout sẽ rất muộn:

var start = Date.now();

// expecting something close to 500
setTimeout(function(){ console.log(Date.now() - start); }, 500);

// fiddle with the number of iterations depending on how quick your machine is
for(var i=0; i<5000000; ++i){}

Trừ khi trình thông dịch tối ưu hóa vòng lặp đi (điều này không có trên chrome), bạn sẽ nhận được thứ gì đó trong hàng nghìn. Tháo vòng lặp và bạn sẽ thấy nó là 500 trên mũi ...


9

Cách duy nhất để đảm bảo mã được thực thi là đặt logic setTimeout của bạn trong một quy trình khác.

Sử dụng mô-đun quy trình con để tạo ra một chương trình node.js mới thực hiện logic của bạn và truyền dữ liệu cho quy trình đó thông qua một số loại luồng (có thể là tcp).

Bằng cách này, ngay cả khi một số mã chặn dài đang chạy trong quy trình chính của bạn, quy trình con của bạn đã tự bắt đầu và đặt một setTimeout trong một quy trình mới và một chuỗi mới và do đó sẽ chạy khi bạn mong đợi.

Sự phức tạp hơn nữa là ở cấp độ phần cứng, nơi bạn có nhiều luồng chạy hơn sau đó xử lý và do đó việc chuyển đổi ngữ cảnh sẽ gây ra sự chậm trễ (rất nhỏ) so với thời gian dự kiến ​​của bạn. Điều này không thể bỏ qua và nếu có vấn đề, bạn cần nghiêm túc xem xét những gì bạn đang cố gắng làm, tại sao bạn cần độ chính xác như vậy và loại phần cứng thay thế thời gian thực nào có sẵn để thực hiện công việc đó.

Nói chung, việc sử dụng các quy trình con và chạy nhiều ứng dụng nút như các quy trình riêng biệt cùng với bộ cân bằng tải hoặc lưu trữ dữ liệu được chia sẻ (như redis) là điều quan trọng để mở rộng mã của bạn.


9

setTimeoutlà một loại Thread , nó chứa một hoạt động trong một thời gian nhất định và thực thi.

setTimeout(function,time_in_mills);

ở đây đối số đầu tiên phải là một kiểu hàm; như một ví dụ nếu bạn muốn in tên của mình sau 3 giây, mã của bạn sẽ giống như bên dưới.

setTimeout(function(){console.log('your name')},3000);

Điểm chính cần nhớ là, bạn muốn làm gì bằng setTimeoutphương pháp này, hãy thực hiện nó bên trong một hàm . Nếu bạn muốn gọi một số phương thức khác bằng cách phân tích cú pháp một số tham số, mã của bạn sẽ giống như bên dưới:

setTimeout(function(){yourOtherMethod(parameter);},3000);

8

setTimeout(callback,t)được sử dụng để chạy lệnh gọi lại sau ít nhất t mili giây . Độ trễ thực tế phụ thuộc vào nhiều yếu tố bên ngoài như độ chi tiết của bộ hẹn giờ hệ điều hành và tải hệ thống.

Vì vậy, có khả năng nó sẽ được gọi một chút sau thời gian đã định, nhưng sẽ không bao giờ được gọi trước đó.

Bộ hẹn giờ không được kéo dài hơn 24,8 ngày.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.