NodeJS - setTimeout (fn, 0) เทียบกับ setImmediate (fn)


คำตอบ:


72

setTimeoutก็เหมือนกับการเรียกใช้ฟังก์ชันหลังจากการหน่วงเวลาเสร็จสิ้น เมื่อใดก็ตามที่มีการเรียกใช้ฟังก์ชันจะไม่ถูกเรียกใช้งานทันที แต่อยู่ในคิวเพื่อให้ดำเนินการหลังจากที่ตัวจัดการเหตุการณ์ที่ดำเนินการและที่จัดคิวในปัจจุบันเสร็จสิ้นก่อน setTimeout (, 0) โดยพื้นฐานแล้วหมายถึงการดำเนินการหลังจากที่ฟังก์ชันปัจจุบันทั้งหมดในคิวปัจจุบันได้รับการดำเนินการ ไม่สามารถรับประกันได้ว่าจะใช้เวลานานเท่าใด

setImmediateมีความคล้ายคลึงกันในเรื่องนี้ยกเว้นว่าจะไม่ใช้คิวของฟังก์ชัน ตรวจสอบคิวของตัวจัดการเหตุการณ์ I / O หากเหตุการณ์ I / O ทั้งหมดในสแน็ปช็อตปัจจุบันถูกประมวลผลเหตุการณ์นั้นจะเรียกใช้การเรียกกลับ มันเข้าคิวทันทีหลังจากตัวจัดการ I / O ตัวสุดท้ายที่ค่อนข้างคล้ายกับ process.nextTick ดังนั้นจึงเร็วกว่า

นอกจากนี้ (setTimeout, 0) จะช้าเพราะจะตรวจสอบตัวจับเวลาอย่างน้อยหนึ่งครั้งก่อนดำเนินการ ในบางครั้งอาจช้าเป็นสองเท่า นี่คือเกณฑ์มาตรฐาน

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})

เอาต์พุต

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)

คนแรกให้ความคิดของการโทรที่เร็วที่สุด คุณสามารถตรวจสอบตัวเองได้ว่า setTimeout ถูกเรียกครึ่งหนึ่งกี่ครั้ง โปรดจำไว้ว่า setImmediate จะปรับตามการเรียกระบบไฟล์ของคุณ ดังนั้นภายใต้การโหลดมันจะทำงานน้อยลง ฉันไม่คิดว่า setTimeout จะทำได้ดีกว่านี้

setTimeout เป็นวิธีการเรียกใช้ฟังก์ชันที่ไม่ล่วงล้ำหลังจากผ่านไประยะหนึ่ง มันเหมือนกับในเบราว์เซอร์ อาจไม่เหมาะสำหรับฝั่งเซิร์ฟเวอร์ (คิดว่าทำไมฉันถึงใช้ benchmark.js ไม่ใช่ setTimeout)


3
สิ่งสำคัญคือต้องทราบว่า setTimeout อาจมีการหน่วงเวลาบังคับอย่างน้อยสี่มิลลิวินาทีหากซ้อนกันห้าครั้ง ดูข้อมูลจำเพาะ html
Jack Allan

แหล่งข้อมูลนี้ (จากคำตอบอื่น) ดูเหมือนจะหักล้างข้อความบางส่วนที่นี่: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev

17

บทความดีๆเกี่ยวกับการทำงานของลูปเหตุการณ์และการล้างความเข้าใจผิดบางอย่าง http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

อ้างถึงบทความ:

setImmediateการโทรกลับจะถูกเรียกหลังจากการโทรกลับของคิว I / O เสร็จสิ้นหรือหมดเวลา การเรียกกลับ setImmediate จะอยู่ใน Check Queue ซึ่งประมวลผลหลังจาก I / O Queue

setTimeout(fn, 0)การโทรกลับจะอยู่ใน Timer Queue และจะถูกเรียกหลังจากการโทรกลับของ I / O เช่นเดียวกับการเรียกกลับของ Check Queue ในฐานะลูปเหตุการณ์ให้ประมวลผลคิวตัวจับเวลาก่อนในการวนซ้ำแต่ละครั้งดังนั้นคิวใดจะถูกดำเนินการก่อนจึงขึ้นอยู่กับว่าลูปเหตุการณ์เฟสใด


คิว setTimeout ถูกประมวลผลก่อนการเรียกกลับ I / O ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
human

4

setImmediate ()คือกำหนดเวลาดำเนินการเรียกกลับทันทีหลังจากการเรียกกลับเหตุการณ์ I / O และก่อน setTimeout และ setInterval

setTimeout ()คือการกำหนดเวลาการดำเนินการโทรกลับครั้งเดียวหลังจากล่าช้าในมิลลิวินาที

นี่คือสิ่งที่เอกสารกล่าว

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

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

หากคุณเรียกใช้โค้ดด้านบนผลลัพธ์จะเป็นเช่นนี้ ... แม้ว่าเอกสารปัจจุบันจะระบุว่า "เพื่อกำหนดเวลาการเรียกกลับ" ทันที "หลังจากการเรียกกลับเหตุการณ์ I / O และก่อน setTimeout และ setInterval" ..

ผลลัพธ์..

setTimeout

setImmediate

หากคุณรวมตัวอย่างของคุณในตัวจับเวลาอื่นมันจะพิมพ์ setImmediate ตามด้วย setTimeout เสมอ

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

แล้วคุณจะชอบอีกแบบเมื่อไหร่?
Shlomi Schwartz

23
คุณไม่ได้อธิบายว่าทำไมสิ่งที่คุณแสดงจึงเกิดขึ้น คำตอบนี้ไม่มีประโยชน์สำหรับฉัน
Clint Eastwood

3
@Savannah ในผลลัพธ์แรกของคุณโปรดอธิบายว่าเหตุใด setTimeout จึงดำเนินการก่อน setImmediate
Agus Syahputra

2
@AgusSyahputra ตรวจสอบสิ่งนี้: github.com/nodejs/node-v0.x-archive/issues/25788
Rodrigo Branas

1
SetImmediate จะไม่ดำเนินการก่อน setTimeout และ setInterval ตลอดเวลา
Midhun GS

2

ใช้เสมอsetImmediateเว้นแต่คุณจะแน่ใจจริงๆว่าคุณต้องการsetTimeout(,0)(แต่ฉันนึกไม่ออกว่ามีไว้เพื่ออะไร) setImmediateการโทรกลับมักจะถูกดำเนินการก่อนเสมอsetTimeout(,0)ยกเว้นเมื่อถูกเรียกในขีดแรกและในการsetImmediateโทรกลับ


1
ฉันจะบอกว่าเหตุผลหลักในการใช้ setTimeout แทน setImmediate คือโค้ดของคุณจะต้องดำเนินการโดยเบราว์เซอร์ที่ไม่ได้ติดตั้ง setImmediate ถึงอย่างนั้นคุณก็สามารถสร้าง shim ได้
Gregory Magarshak

9
นี่เป็นคำแนะนำที่ไม่น่าเชื่อ หากทุกอย่างขอให้ดำเนินการก่อนลักษณะประสิทธิภาพที่เกิดขึ้นใหม่ของการดำเนินการแบบอะซิงโครนัสจะเป็นขยะเมื่อเทียบกับการจัดคิวในตอนท้าย setTimeoutควรเป็นทางเลือกและsetImmediateใช้เมื่อจำเป็นเท่านั้น
Rich Remer

1

ไม่พอใจกับคำตอบที่ให้มาโดยสิ้นเชิง ฉันโพสต์สิ่งที่ฉันคิดว่าเป็นคำตอบที่ดีกว่าที่นี่: https://stackoverflow.com/a/56724489/5992714

คำถามเป็นไปได้ว่าทำไมพฤติกรรมของ setTimeout (0) และ setImmediate () จึงไม่ได้กำหนดเมื่อใช้ในโมดูลหลัก


1
โปรดอย่าโพสต์คำตอบเดียวกันทุกประการสำหรับคำถามสองข้อ หากคำถามแตกต่างกันให้ปรับแต่งคำตอบสำหรับแต่ละข้อ หากเหมือนกันให้ตั้งค่าสถานะหรือโหวตเพื่อปิดรายการที่ซ้ำกัน
Tom Zych

@TomZych ตั้งข้อสังเกต.
มนุษย์

0

ฉันคิดว่าคำตอบของNavya Sไม่ถูกต้องนี่คือรหัสทดสอบของฉัน:

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);

คำอธิบายอยู่ที่นี่


0

setTimeout (fn, 0) สามารถใช้เพื่อป้องกันไม่ให้เบราว์เซอร์ค้างในการอัปเดตขนาดใหญ่ ตัวอย่างเช่นใน websocket.onmessage คุณอาจมีการเปลี่ยนแปลง html และหากมีข้อความมาเรื่อย ๆ เบราว์เซอร์อาจหยุดทำงานเมื่อใช้ setImmidiate


0

หากต้องการทำความเข้าใจอย่างลึกซึ้งโปรดผ่านขั้นตอนการวนซ้ำของเหตุการณ์

SetImmediate: จะดำเนินการในขั้นตอน "ตรวจสอบ" ตรวจสอบขั้นตอนการเรียกว่าหลังจากเฟส I / O,

SetTimeOut: จะดำเนินการในระยะ "ตัวจับเวลา" จับเวลาคือระยะแรก แต่จะเรียกว่าหลังจากที่I / Oขั้นตอนเช่นเดียวกับการตรวจสอบขั้นตอน

เพื่อให้ได้ผลลัพธ์ในลักษณะดีเทอร์มินิสติกจะขึ้นอยู่กับเฟสที่เหตุการณ์ลูปคือ ดังนั้นเราจึงสามารถใช้ฟังก์ชันจากสองฟังก์ชันได้


-5

ใช้ setImmediate () เพื่อไม่ปิดกั้นห่วงเหตุการณ์ การเรียกกลับจะทำงานในลูปเหตุการณ์ถัดไปทันทีที่การดำเนินการปัจจุบันเสร็จสิ้น

ใช้ setTimeout () เพื่อควบคุมความล่าช้า ฟังก์ชันจะทำงานหลังจากการหน่วงเวลาที่กำหนด ความล่าช้าขั้นต่ำคือ 1 มิลลิวินาที

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.