NodeJS - setTimeout (fn, 0) vs setImmediate (fn)

Jawaban:

72

setTimeout sama seperti memanggil fungsi setelah penundaan selesai. Setiap kali sebuah fungsi dipanggil, itu tidak segera dijalankan, tetapi antri sehingga dijalankan setelah semua eventhandler yang sedang dieksekusi dan antri selesai terlebih dahulu. setTimeout (, 0) pada dasarnya berarti mengeksekusi setelah semua fungsi saat ini dalam antrian saat ini dijalankan. Tidak ada jaminan tentang berapa lama waktu yang dibutuhkan.

setImmediate serupa dalam hal ini kecuali bahwa ia tidak menggunakan antrian fungsi. Ia memeriksa antrian eventhandler I / O. Jika semua kejadian I / O dalam snapshot saat ini diproses, callback akan dijalankan. Ini mengantri mereka segera setelah penangan I / O terakhir agak seperti proses.nextTick. Jadi lebih cepat.

Juga (setTimeout, 0) akan lambat karena akan memeriksa pengatur waktu setidaknya sekali sebelum dijalankan. Kadang-kadang bisa dua kali lebih lambat. Ini patokannya.

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

Keluaran

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)

Yang pertama memberikan ide tentang panggilan tercepat. Anda dapat memeriksa diri Anda sendiri jika setTimeout dipanggil setengah kali dari yang lain. Ingat juga setImmediate akan menyesuaikan dengan panggilan sistem file Anda. Jadi di bawah beban itu akan bekerja lebih sedikit. Saya tidak berpikir setTimeout bisa bekerja lebih baik.

setTimeout adalah cara memanggil fungsi yang tidak mengganggu setelah beberapa waktu. Ini seperti di browser. Ini mungkin tidak cocok untuk sisi server (pikirkan mengapa saya menggunakan benchmark.js bukan setTimeout).

pengguna568109
sumber
3
Penting untuk diperhatikan bahwa setTimeout tunduk pada penundaan paksa setidaknya empat milidetik jika bertingkat lima kali. lihat spesifikasi html
Jack Allan
Sumber ini (dari jawaban lain) tampaknya membantah beberapa pernyataan di sini: voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout
Dmitri Zaitsev
17

Artikel bagus tentang cara kerja event loop dan menghapus beberapa kesalahpahaman. http://voidcanvas.com/setimmediate-vs-nexttick-vs-settimeout/

Mengutip artikel:

setImmediatecallback dipanggil setelah I / O Queue callbacks selesai atau waktunya habis. setImmediate callbacks ditempatkan di Check Queue, yang diproses setelah I / O Queue.

setTimeout(fn, 0)callback ditempatkan di Timer Queue dan akan dipanggil setelah callback I / O serta callback Check Queue. Sebagai loop peristiwa, proses antrian pengatur waktu terlebih dahulu di setiap iterasi, sehingga mana yang akan dieksekusi terlebih dahulu tergantung pada loop peristiwa fase mana.

Aman Gupta
sumber
antrian setTimeout diproses sebelum panggilan balik I / O. ref: nodejs.org/en/docs/guides/event-loop-timers-and-nexttick
manusia
4

setImmediate () adalah untuk menjadwalkan eksekusi callback segera setelah kejadian I / O callback dan sebelum setTimeout dan setInterval.

setTimeout () adalah untuk menjadwalkan eksekusi callback satu kali setelah penundaan milidetik.

Inilah yang tertulis dalam dokumen.

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

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

Jika Anda menjalankan kode di atas, hasilnya akan seperti ini ... meskipun dokumen saat ini menyatakan bahwa "Untuk menjadwalkan eksekusi callback" langsung "setelah kejadian I / O callback dan sebelum setTimeout dan setInterval." ..

Hasil..

setTimeout

setImmediate

Jika Anda menggabungkan contoh Anda di timer lain, itu selalu mencetak setImmediate diikuti oleh setTimeout.

setTimeout(function() {
  setTimeout(function() {
    console.log('setTimeout')
  }, 0);
  setImmediate(function() {
    console.log('setImmediate')
  });
}, 10);
Navya S
sumber
Jadi kapan Anda akan memilih salah satu dari yang lain?
Shlomi Schwartz
23
Anda tidak menjelaskan mengapa apa yang Anda tunjukkan terjadi. Jawaban ini tidak berguna bagi saya.
Clint Eastwood
3
@Savannah Di hasil pertama Anda, jelaskan mengapa setTimeout dieksekusi terlebih dahulu sebelum setImmediate
Agus Syahputra
2
@AgusSyahputra Lihat ini: github.com/nodejs/node-v0.x-archive/issues/25788
Rodrigo Branas
1
SetImmediate tidak akan dieksekusi sebelum setTimeout dan setInterval sepanjang waktu
Midhun GS
2

selalu gunakan setImmediate, kecuali jika Anda benar-benar yakin bahwa Anda membutuhkannya setTimeout(,0)(tetapi saya bahkan tidak dapat membayangkan, untuk apa). setImmediatecallback akan hampir selalu dijalankan sebelumnya setTimeout(,0), kecuali saat dipanggil di tik pertama dan di setImmediatecallback.

vkurchatkin.dll
sumber
1
Saya akan mengatakan alasan utama untuk menggunakan setTimeout daripada setImmediate adalah kode Anda perlu dijalankan oleh browser yang tidak menerapkan setImmediate. Meski begitu, Anda bisa membuat shim.
Gregory Magarshak
9
Ini adalah nasihat yang tidak masuk akal. Jika semuanya meminta untuk pergi dulu, karakteristik kinerja yang muncul dari eksekusi asinkron akan menjadi sampah dibandingkan dengan antrian di akhir. setTimeoutharus menjadi tujuan, dengan setImmediatedigunakan hanya jika terbukti perlu.
Rich Remer
1

Benar-benar tidak puas dengan jawaban yang diberikan. Saya memposting apa yang menurut saya merupakan jawaban yang lebih baik di sini: https://stackoverflow.com/a/56724489/5992714

Pertanyaan adalah kemungkinan duplikat dari Mengapa perilaku setTimeout (0) dan setImmediate () tidak ditentukan ketika digunakan dalam modul utama?

manusia
sumber
1
Harap jangan memposting jawaban yang persis sama untuk dua pertanyaan. Jika pertanyaannya berbeda, sesuaikan jawaban untuk masing-masing pertanyaan. Jika keduanya sama, tandai atau pilih untuk menutup salah satu sebagai duplikat.
Tom Zych
@Tomych mencatat.
manusia
0

Saya rasa jawaban Navya S tidak benar, berikut kode tes saya:

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

Penjelasannya ada di sini

笑笑 十年
sumber
0

setTimeout (fn, 0) dapat digunakan untuk mencegah browser membeku dalam pembaruan besar-besaran. misalnya di websocket.onmessage, Anda mungkin memiliki perubahan html, dan jika pesan terus datang, browser mungkin berhenti saat menggunakan setImmidiate

Lior Goldemberg
sumber
0

Untuk memahaminya secara mendalam, harap sekali melalui fase loop peristiwa.

SetImmediate: Ini dijalankan pada fase "check". The cek fase disebut setelah fase I / O.

SetTimeOut: Ini dijalankan dalam fase "timer". The Timer fase adalah tahap pertama tetapi disebut setelah I / O fase serta Periksa fase.

Untuk mendapatkan keluaran secara deterministik, itu akan tergantung pada fase mana loop-peristiwa itu berada; karenanya, kita dapat menggunakan fungsi dari dua fungsi tersebut.

kanika sharma
sumber
-5

gunakan setImmediate () untuk tidak memblokir event loop. Callback akan berjalan pada loop acara berikutnya, segera setelah yang sekarang selesai.

gunakan setTimeout () untuk penundaan terkontrol. Fungsi akan berjalan setelah penundaan yang ditentukan. Penundaan minimum adalah 1 milidetik.

Andras
sumber