NodeJS - setTimeout (fn, 0) so với setIm Instant (fn)


Câu trả lời:


71

setTimeout đơn giản giống như việc gọi hàm sau khi kết thúc thời gian trễ. Bất cứ khi nào một hàm được gọi, nó không được thực thi ngay lập tức, mà được xếp hàng đợi để nó được thực thi sau khi tất cả các bộ xử lý sự kiện đang thực thi và hiện đang xếp hàng kết thúc trước. setTimeout (, 0) về cơ bản có nghĩa là thực thi sau khi tất cả các hàm hiện tại trong hàng đợi hiện tại được thực thi. Không có đảm bảo nào có thể được thực hiện về thời gian có thể mất.

setIm Instant cũng tương tự về vấn đề này ngoại trừ việc nó không sử dụng hàng đợi các hàm. Nó kiểm tra hàng đợi của các bộ xử lý sự kiện I / O. Nếu tất cả các sự kiện I / O trong ảnh chụp nhanh hiện tại được xử lý, nó sẽ thực hiện gọi lại. Nó xếp hàng chúng ngay sau trình xử lý I / O cuối cùng giống như process.nextTick. Vì vậy, nó là nhanh hơn.

Ngoài ra (setTimeout, 0) sẽ chậm vì nó sẽ kiểm tra bộ đếm thời gian ít nhất một lần trước khi thực thi. Đôi khi nó có thể chậm gấp đôi. Đây là một điểm chuẩn.

var Suite = require('benchmark').Suite
var fs = require('fs')

var suite = new Suite

suite.add('deffered.resolve()', function(deferred) {
  deferred.resolve()
}, {defer: true})

suite.add('setImmediate()', function(deferred) {
  setImmediate(function() {
    deferred.resolve()
  })
}, {defer: true})

suite.add('setTimeout(,0)', function(deferred) {
  setTimeout(function() {
    deferred.resolve()
  },0)
}, {defer: true})

suite
.on('cycle', function(event) {
  console.log(String(event.target));
})
.on('complete', function() {
  console.log('Fastest is ' + this.filter('fastest').pluck('name'));
})
.run({async: true})

Đầu ra

deffered.resolve() x 993 ops/sec ±0.67% (22 runs sampled)
setImmediate() x 914 ops/sec ±2.48% (57 runs sampled)
setTimeout(,0) x 445 ops/sec ±2.79% (82 runs sampled)

Người đầu tiên đưa ra ý tưởng về các cuộc gọi nhanh nhất có thể. Bạn có thể tự kiểm tra xem setTimeout có được gọi nhiều hơn một nửa so với những lần khác hay không. Cũng nên nhớ setIm Instant sẽ điều chỉnh các lệnh gọi hệ thống tệp của bạn. Vì vậy, dưới tải nó sẽ hoạt động ít hơn. Tôi không nghĩ rằng setTimeout có thể làm tốt hơn.

setTimeout là cách gọi hàm không xâm phạm sau một thời gian. Nó giống như trong trình duyệt. Nó có thể không phù hợp với phía máy chủ (hãy nghĩ tại sao tôi sử dụng benchmark.js không phải setTimeout).


3
Điều quan trọng cần lưu ý là setTimeout phải chịu độ trễ bắt buộc ít nhất bốn mili giây nếu được lồng năm lần. xem thông số kỹ thuật html
Jack Allan

Nguồn tin này (từ câu trả lời khác) dường như để bác bỏ một số những điều khoản ở đây: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev

17

Một bài viết tuyệt vời về cách hoạt động của vòng lặp sự kiện và xóa một số quan niệm sai lầm. http://voidcanvas.com/setim ngay-vs-nexttick-vs-settimeout/

Trích dẫn bài báo:

setImmediategọi lại được gọi sau khi gọi lại Hàng đợi I / O kết thúc hoặc hết thời gian. Các lệnh gọi lại setIm ngay được đặt trong Hàng đợi Kiểm tra, được xử lý sau Hàng đợi I / O.

setTimeout(fn, 0)các lệnh gọi lại được đặt trong Hàng đợi Bộ hẹn giờ và sẽ được gọi sau các lệnh gọi lại I / O cũng như các lệnh gọi lại Kiểm tra Hàng đợi. Là vòng lặp sự kiện, xử lý hàng đợi bộ đếm thời gian đầu tiên trong mỗi lần lặp, vì vậy cái nào sẽ được thực hiện trước tùy thuộc vào vòng lặp sự kiện pha nào.


Hàng đợi setTimeout được xử lý trước khi I / O gọi lại. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
con người

6

setIm Instant () là lập lịch thực hiện lệnh gọi lại ngay lập tức sau các lần gọi lại sự kiện I / O và trước setTimeout và setInterval.

setTimeout () là lên lịch thực hiện lệnh gọi lại một lần sau mili giây trễ.

Đây là những gì các tài liệu nói.

setTimeout(function() {
  console.log('setTimeout')
}, 0)

setImmediate(function() {
  console.log('setImmediate')
})

Nếu bạn chạy đoạn mã trên, kết quả sẽ như thế này ... mặc dù tài liệu hiện tại nói rằng "Để lập lịch thực hiện lệnh gọi lại" ngay lập tức "sau các lần gọi lại sự kiện I / O và trước setTimeout và setInterval." ..

Kết quả..

setTimeout

setIm Instant

Nếu bạn bọc ví dụ của mình trong một bộ đếm thời gian khác, nó luôn in setIm ngay sau đó là setTimeout.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);

Vậy khi nào bạn sẽ thích cái này hơn cái kia?
Shlomi Schwartz,

21
Bạn đã không giải thích tại sao những gì bạn thể hiện xảy ra. Câu trả lời này không hữu ích cho tôi.
Clint Eastwood

3
@Savannah Trong kết quả đầu tiên của bạn, hãy giải thích lý do tại sao setTimeout thực hiện đầu tiên trước khi setImmediate
Agus Syahputra


1
SetImmediate wont thực hiện trước khi setTimeout và setInterval mọi thời điểm
Mithun GS

2

luôn luôn sử dụng setImmediate, trừ khi bạn thực sự chắc chắn rằng bạn cần setTimeout(,0)(nhưng tôi thậm chí không thể tưởng tượng, để làm gì). setImmediatecallback hầu như sẽ luôn được thực hiện trước đó setTimeout(,0), ngoại trừ khi được gọi trong lần đánh dấu đầu tiên và trong lần setImmediategọi lại.


1
Tôi sẽ nói lý do chính để sử dụng setTimeout thay vì setIm Instant là mã của bạn cần được thực thi bởi các trình duyệt chưa triển khai setIm ngay. Thậm chí sau đó, bạn có thể chỉ cần tạo một miếng chêm.
Gregory Magarshak

9
Đây là lời khuyên khó tin. Nếu mọi thứ yêu cầu thực hiện trước, các đặc tính hiệu suất nổi lên của thực thi không đồng bộ sẽ trở thành rác so với xếp hàng ở cuối. setTimeoutchỉ nên setImmediatesử dụng khi cần thiết.
Rich Remer

1

Hoàn toàn không hài lòng với các câu trả lời được cung cấp. Tôi đã đăng những gì tôi nghĩ là câu trả lời tốt hơn ở đây: https://stackoverflow.com/a/56724489/5992714

Các câu hỏi có thể trùng lặp với Tại sao hành vi của setTimeout (0) và setIm Instant () không được xác định khi được sử dụng trong mô-đun chính?


1
Vui lòng không đăng cùng một câu trả lời cho hai câu hỏi. Nếu các câu hỏi khác nhau, hãy điều chỉnh câu trả lời cho từng câu hỏi. Nếu chúng giống nhau, hãy gắn cờ hoặc bỏ phiếu để đóng một địa chỉ trùng lặp.
Tom Zych

@TomZych lưu ý.
con người

0

Tôi nghĩ câu trả lời của Navya S là không đúng, đây là mã thử nghiệm của tôi:

let set = new Set();

function orderTest() {
  let seq = [];
  let add = () => set.add(seq.join());
  setTimeout(function () {
    setTimeout(function () {
      seq.push('setTimeout');
      if (seq.length === 2) add();
    }, 0);

    setImmediate(function () {
      seq.push('setImmediate');
      if (seq.length === 2) add();
    });
  }, 10);
}

// loop 100 times
for (let i = 0; i < 100; i++) {
  orderTest();
}

setTimeout(() => {
  // will print one or two items, it's random
  for (item of set) {
    console.log(item);
  }
}, 100);

Những lời giải thích ở đây


0

setTimeout (fn, 0) có thể được sử dụng để ngăn trình duyệt bị đóng băng trong bản cập nhật lớn. ví dụ: trong websocket.onmessage, bạn có thể có các thay đổi về html và nếu các thông báo tiếp tục đến, trình duyệt có thể bị treo khi sử dụng setImmidiate


0

Để hiểu sâu về chúng, vui lòng xem qua các giai đoạn của vòng lặp sự kiện.

SetIm Instant: Nó được thực thi trong giai đoạn "kiểm tra". Các kiểm tra giai đoạn được gọi là sau giai đoạn I / O.

SetTimeOut: Nó được thực thi trong giai đoạn "hẹn giờ". Các bộ đếm thời gian giai đoạn là giai đoạn đầu tiên nhưng được gọi sau khi I / O giai đoạn cũng như Kiểm tra giai đoạn.

Để có được kết quả đầu ra một cách xác định, nó sẽ phụ thuộc vào giai đoạn nào của vòng lặp sự kiện; theo đó, chúng ta có thể sử dụng hàm trong số hai.


-4

sử dụng setIm Instant () để không chặn vòng lặp sự kiện. Cuộc gọi lại sẽ chạy trên vòng lặp sự kiện tiếp theo, ngay sau khi vòng lặp hiện tại được thực hiện.

sử dụng setTimeout () để kiểm soát độ trễ. Hàm sẽ chạy sau độ trễ đã chỉ định. Độ trễ tối thiểu là 1 mili giâ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.