Sự khác biệt giữa hai cái đó là gì, và khi nào tôi sẽ sử dụng cái này thay cho cái kia?
Sự khác biệt giữa hai cái đó là gì, và khi nào tôi sẽ sử dụng cái này thay cho cái kia?
Câu trả lời:
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).
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.
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);
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.
setTimeoutchỉ nên setImmediatesử dụng khi cần thiết.
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?
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
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
Để 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.