setImmediate ve nextTick


336

Node.js sürüm 0.10 bugün yayınlandı ve tanıtıldı setImmediate. API değişiklikleri belgeler özyinelemeli yaparken kullanmaktan önerir nextTickaramaları.

Kadarıyla MDN diyor o kadar çok benziyor process.nextTick.

Ne zaman nextTickve ne zaman kullanmalıyım setImmediate?


20
Blogda bu değişiklikle ilgili 5 paragraf var blog.nodejs.org/2013/03/11/node-v0-10-0-stable
mak

1
Performans ölçütlerine nextTickgöre setImmediate, büyük hesaplamalardan daha hızlı görünüyor .

10
Kayıt için, önce bu beş paragrafı okudum ve benim için hiçbir şeyi temizlemediğinde hala bu soruya son verdim. Kabul edilen cevap çok daha özlüdür ve aslında setImmediatedaha iyi olanı açıklar .
Chev

Blogumdaki farkı ayrıntılı olarak açıkladım .
plafer

GC daha önce çalışabilir setImmediate, ancak daha önce çalışamaz nextTickmı?

Yanıtlar:


510

setImmediateİşlevi zaten olay kuyruğunda olan G / Ç olay geri çağrılarının arkasına sıralamak istiyorsanız kullanın . process.nextTickEtkinliğin tamamlanmasından hemen sonra çalışacak şekilde, olay kuyruğunun başındaki işlevi etkili bir şekilde sıralamak için kullanın .

Bu nedenle, özyineleme kullanarak uzun süre çalışan, CPU'ya bağlı bir işi bölmeye çalıştığınız bir durumda, şimdi bir sonraki yinelemeyi sıralamak setImmediateyerine kullanmak istersiniz process.nextTick, aksi takdirde herhangi bir G / Ç olay geri çağırma şansı elde edemez yinelemeler arasında koşmak.


86
Process.nextTick öğesine iletilen geri çağrılar genellikle geçerli yürütme akışının sonunda çağrılır ve dolayısıyla bir işlevi eşzamanlı olarak çağırmak kadar hızlıdır. İşaretlenmediğinde, bu olay döngüsünü aç bırakarak herhangi bir G / Ç oluşmasını önler. setImmediates, oluşturulan sıraya göre kuyruğa alınır ve döngü yinelemesi başına kuyruktan bir kez çıkarılır. Bu, yineleme başına process.maxTickDepth kuyruğa alınmış geri çağrıları yürütecek olan process.nextTick'ten farklıdır. setImmediate, G / Ç'nin aç bırakılmadığından emin olmak için sıraya alınmış bir geri çağrıyı tetikledikten sonra olay döngüsüne ulaşır.
Benjamin Gruenbaum

2
@UstamanSangat setImmediate, yalnızca IE10 + tarafından desteklenmektedir, diğer tüm tarayıcılar, Microsoft tarafından dövülmeyi sevmedikleri için gelecekteki olası standardı uygulamayı reddetmektedir. FF / Chrome'da benzer bir sonuç elde etmek için postMessage'ı kullanabilirsiniz (kendi pencerenize bir mesaj gönderin). Özellikle güncellemeleriniz kullanıcı arayüzü ile ilgiliyse requestAnimationFrame'i de kullanabilirsiniz. setTimeout (func, 0) process.nextTick gibi çalışmaz.
fabspro

45
@fabspro "çünkü Microsoft'umu dövmekten hoşlanmıyorlar" size bir şey hakkında acı veriyor. Çoğunlukla korkunç, korkunç bir şekilde adlandırılmış olması nedeniyle. Bir kez setImmediate işlevi asla çalışmayacak, hemen çalışmayacak. Fonksiyonun adı yaptığı şeyin tam tersidir. nextTick ve setImmediate, geçiş yapmaktan daha iyi olurdu; setImmediate, geçerli yığın tamamlandıktan hemen sonra (G / Ç'yi beklemeden önce) ve nextTick, bir sonraki tıklamanın sonunda (G / Ç'yi bekledikten sonra) yürütür. Ama sonra, bu zaten binlerce kez söylendi.
Craig Andrews

4
@fabspro Ama maalesef bu fonksiyon nextTick olarak adlandırılıyor. setImmediate bir setTimeout / postMessage'a benzerken nextTick "hemen" yürütür.
Robert

1
@CraigAndrews Her requestAnimationFramezaman gerçekleşmediği için kaçınırdım (bunu kesinlikle gördüm, örnek sekmenin geçerli sekme olmadığını düşünüyorum) ve sayfa boyama işlemini tamamlamadan önce çağrılabilir (yani tarayıcı hala meşgul resim).
Mart'ta robocat

68

Örnek olarak

import fs from 'fs';
import http from 'http';

const options = {
  host: 'www.stackoverflow.com',
  port: 80,
  path: '/index.html'
};

describe('deferredExecution', () => {
  it('deferredExecution', (done) => {
    console.log('Start');
    setTimeout(() => console.log('TO1'), 0);
    setImmediate(() => console.log('IM1'));
    process.nextTick(() => console.log('NT1'));
    setImmediate(() => console.log('IM2'));
    process.nextTick(() => console.log('NT2'));
    http.get(options, () => console.log('IO1'));
    fs.readdir(process.cwd(), () => console.log('IO2'));
    setImmediate(() => console.log('IM3'));
    process.nextTick(() => console.log('NT3'));
    setImmediate(() => console.log('IM4'));
    fs.readdir(process.cwd(), () => console.log('IO3'));
    console.log('Done');
    setTimeout(done, 1500);
  });
});

Aşağıdaki çıktıyı verecektir

Start
Done
NT1
NT2
NT3
TO1
IO2
IO3
IM1
IM2
IM3
IM4
IO1

Umarım bu farkı anlamaya yardımcı olabilir.

Güncellenmiş:

process.nextTick()SetImmediate () ile yürütme, sırada bekleyen herhangi bir G / Ç olayının arkasında sıraya alınırken, diğer G / Ç olayları tetiklenmeden önce çalıştırmayla ertelenen geri çağrılar.

Node.js Tasarım Desenleri , yazan Mario Casciaro (muhtemelen node.js / js hakkında en iyi kitap)


2
Bu gerçekten faydalı teşekkürler. Bence görüntüler ve örnekler bir şeyi anlamanın en hızlı yolu.
John James

1
SetTimeout () ve setImmediate () bir G / Ç döngüsü içinde değilken, bir işlemin performansına bağlı olarak siparişin deterministik olmadığını belirtmek önemlidir. nodejs.org/tr/docs/guides/event-loop-timers-and-nexttick For example, if we run the following script which is not within an I/O cycle (i.e. the main module), the order in which the two timers are executed is non-deterministic, as it is bound by the performance of the process: Yani, bu cevap tam olarak farklılığa cevap vermiyor, sadece farklı bağlamlarda değişebilecek bir örnek
Actung

@Actung tarafından işaret edildiği gibi. sonucu belirlemek için setTimetout ve setImmediate öğelerinin bir G / Ç döngüsü içinde olup olmadığını bilmek çok önemlidir.
Rajika Imal

50

Sanırım bunu gayet güzel bir şekilde açıklayabilirim. Yana nextTickyinelemeli çağırmak devam etmesini olay döngü engelleme sonunda olabilir, şimdiki operasyonun sonunda denir. setImmediatebunu olay döngüsünün kontrol aşamasında ateşleyerek olay döngüsünün normal şekilde devam etmesini sağlayarak çözer.

   ┌───────────────────────┐
┌─>│        timers         
  └──────────┬────────────┘
  ┌──────────┴────────────┐
       I/O callbacks     
  └──────────┬────────────┘
  ┌──────────┴────────────┐
       idle, prepare     
  └──────────┬────────────┘      ┌───────────────┐
  ┌──────────┴────────────┐         incoming:   
           poll          │<─────┤  connections, 
  └──────────┬────────────┘         data, etc.  
  ┌──────────┴────────────┐      └───────────────┘
          check          
  └──────────┬────────────┘
  ┌──────────┴────────────┐
└──┤    close callbacks    
   └───────────────────────┘

kaynak: https://nodejs.org/en/docs/guides/event-loop-timers-and-nexttick/

Kontrol aşamasının anket aşamasından hemen sonra olduğuna dikkat edin. Bunun nedeni, anket aşaması ve G / Ç geri çağrılarının, aramalarınızın gerçekleştirileceği en olası yerler olmasıdır setImmediate. İdeal olarak, bu çağrıların çoğu aslında hemen gerçekleşecek, nextTickher işlemden sonra kontrol edilen ve teknik olarak olay döngüsünün dışında var olan hemen değil .

setImmediateVe arasındaki farkın küçük bir örneğine bakalım process.nextTick:

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from setImmediate handler.
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
  });
}
step(0);

Diyelim ki bu programı yeni çalıştırdık ve olay döngüsünün ilk yinelemesinden geçiyoruz. İçine arayacak stepyineleme sıfır ile fonksiyonu. Daha sonra iki işleyicileri, diğeri kaydedecektir setImmediateve bir tane process.nextTick. Daha sonra bu işlevi bir setImmediatesonraki kontrol aşamasında çalışacak olan işleyiciden özyineli olarak çağırırız . nextTickİşleyicisi ikinci kaydedildi aslında ilk çalışacağı, böylece bile olsa olay döngü kesintiye Mevcut işlemin sonunda çalışacaktır.

Sıra şu şekilde biter: nextTickgeçerli işlem sona erdiğinde tetiklenir, bir sonraki olay döngüsü başlar, normal olay döngü aşamaları yürütülür, tetiklenir ve işlemi tekrar tekrar başlatmak için işlevimizi setImmediateyinelemeli olarak çağırır step. Geçerli işlem sona erer, nextTickyangınlar vb.

Yukarıdaki kodun çıktısı:

nextTick iteration: 0
setImmediate iteration: 0
nextTick iteration: 1
setImmediate iteration: 1
nextTick iteration: 2
setImmediate iteration: 2
nextTick iteration: 3
setImmediate iteration: 3
nextTick iteration: 4
setImmediate iteration: 4
nextTick iteration: 5
setImmediate iteration: 5
nextTick iteration: 6
setImmediate iteration: 6
nextTick iteration: 7
setImmediate iteration: 7
nextTick iteration: 8
setImmediate iteration: 8
nextTick iteration: 9
setImmediate iteration: 9

Şimdi özyinelemeli çağrımızı yerine stepbizim nextTickişleyicimize taşıyalım setImmediate.

function step(iteration) {
  if (iteration === 10) return;
  setImmediate(() => {
    console.log(`setImmediate iteration: ${iteration}`);
  });
  process.nextTick(() => {
    console.log(`nextTick iteration: ${iteration}`);
    step(iteration + 1); // Recursive call from nextTick handler.
  });
}
step(0);

Şimdi biz özyinelemeli çağrı taşımış olduğu stepiçine nextTickfarklı bir sırada davranacaktır işleyici şeyler. Olay döngüsünü ilk yinelememiz çalışır ve stepbir setImmedaiteişleyicinin yanı sıra bir nextTickişleyiciyi kaydetmeyi çağırır . Mevcut işlem sona erdikten sonra, başka bir işleyiciyi ve başka bir işleyiciyi nextTickyinelemeli olarak çağıran stepve kaydeden işleyici yangınlarımız . Bir işleyici geçerli işlemden sonra ateş ettiğinden, bir işleyicinin bir işleyiciye kaydedilmesi , ikinci işleyicinin geçerli işleyici işlemi tamamlandıktan hemen sonra çalışmasına neden olur. İşleyicileri hiç devam etmesini güncel olay döngü önlenmesi, ateş tutacak. Tüm bunlardan geçeceğizsetImmediatenextTicknextTicknextTicknextTicknextTicknextTicktek bir setImmediateişleyici yangını görmeden önce işleyicileri.

Yukarıdaki kodun çıktısı şu şekildedir:

nextTick iteration: 0
nextTick iteration: 1
nextTick iteration: 2
nextTick iteration: 3
nextTick iteration: 4
nextTick iteration: 5
nextTick iteration: 6
nextTick iteration: 7
nextTick iteration: 8
nextTick iteration: 9
setImmediate iteration: 0
setImmediate iteration: 1
setImmediate iteration: 2
setImmediate iteration: 3
setImmediate iteration: 4
setImmediate iteration: 5
setImmediate iteration: 6
setImmediate iteration: 7
setImmediate iteration: 8
setImmediate iteration: 9

Özyinelemeli çağrıyı yarıda kesip 10 yinelemeden sonra iptal nextTicketmeseydik , çağrılar tekrarlamaya devam eder ve olay döngüsünün bir sonraki aşamaya devam etmesine asla izin vermez. Bir sonraki olay döngüsünde ateşlenecek ve bir başka işleyiciyi birinden ayarlamak geçerli olay döngüsünü hiç kesmeyecek ve böylece olay döngüsünün aşamalarını normal şekilde yürütmeye devam etmesine izin verecek şekilde, nextTicközyinelemeli olarak kullanıldığında nasıl engellenebilir .setImmediatesetImmediate

Umarım yardımcı olur!

PS - Diğer yorumcularla, iki işlevin adlarının kolayca değiştirilebileceğine katılıyorum, çünkü nextTickgeçerli olanın sonu yerine bir sonraki olay döngüsünde patlayacak gibi geliyor ve geçerli döngünün sonu daha "hemen" "bir sonraki döngünün başlangıcından daha fazla. Ah, API olgunlaştıkça bunu elde ederiz ve insanlar mevcut arayüzlere bağımlı hale gelirler.


2
Oldukça açık bir açıklama. Bu cevabın daha fazla oy kullanması gerektiğini düşünüyorum.
Actung

İyi açıklandı (Y)
Dhiraj Sharma

Düğüm'ün process.nextTick kullanımı hakkındaki uyarısını yinelemek önemlidir. NextTickQueue'da çok sayıda geri çağırma işlemi yaparsanız, anket fazına hiçbir zaman ulaşılmadığından emin olarak olay döngüsünü aç bırakabilirsiniz. Bu nedenle genellikle setImmediate'i tercih etmelisiniz.
faridcs

1
Teşekkürler, en iyi açıklama buydu. örnek kod gerçekten yardımcı oldu.
skyhavoc

@skyhavoc yardımcı olabildiğime sevindim!
Chev

30

Yanıttaki yorumlarda, nextTick'in Makrosemantik'ten Mikrosemantik'e geçtiğini açıkça belirtmiyor.

0.9 düğümünden önce (setImmediate tanıtıldığında), nextTick, bir sonraki çağrı kaydının başlangıcında çalıştırılır.

0.9 düğümünden beri nextTick, mevcut çağrı kaydının sonunda çalışır, oysa setImmediate bir sonraki çağrı kaydının başındadır

kontrol https://github.com/YuzuJS/setImmediate araçları ve detaylar için


11

Basit bir ifadeyle, process.NextTick () yöntemi, olay döngüsünün bir sonraki işaretinde yürütülür. Ancak, setImmediate, temel olarak setImmediate () altında kaydedilen geri aramanın yalnızca G / Ç geri arama ve yoklama aşamasından sonra çağrılmasını sağlayan ayrı bir faza sahiptir.

Güzel açıklama için lütfen bu bağlantıya bakın: https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and -onun-metrik-c4907b19da4c

basitleştirilmiş olay döngüsü olayları


8

Burada her ikisinin de nasıl çalıştığını açıklayan bazı harika cevaplar.

Sorulan soruyu cevaplayan bir tane eklemeniz yeterlidir:

Ne zaman nextTickve ne zaman kullanmalıyım setImmediate?


Her zaman kullanın setImmediate.


Node.js Olay Döngü, Zamanlayıcılar veprocess.nextTick() doc aşağıdakileri içerir:

Geliştiricilerin setImmediate()her durumda kullanılmasını öneririz çünkü mantık yürütmek daha kolaydır (ve tarayıcı JS gibi daha çeşitli ortamlarla uyumlu kodlara yol açar.)


Daha önce dokümanda process.nextTickyol açabileceği konusunda uyarıyor ...

bazı kötü durumlar, çünkü olay döngüsünün anket aşamasına ulaşmasını engelleyen yinelemeli process.nextTick()çağrılar yaparak G / Ç'nizi "aç bırakmanıza" olanak tanır .

Anlaşıldığı gibi, process.nextTickaçlıktan ölebilir Promises:

Promise.resolve().then(() => { console.log('this happens LAST'); });

process.nextTick(() => {
  console.log('all of these...');
  process.nextTick(() => {
    console.log('...happen before...');
    process.nextTick(() => {
      console.log('...the Promise ever...');
      process.nextTick(() => {
        console.log('...has a chance to resolve');
      })
    })
  })
})

Öte yandan, setImmediate" akıl yürütmesi daha kolaydır " ve bu tür sorunları önler:

Promise.resolve().then(() => { console.log('this happens FIRST'); });

setImmediate(() => {
  console.log('this happens LAST');
})

Dolayısıyla, benzersiz davranışına özel bir ihtiyaç olmadıkça process.nextTick, önerilen yaklaşım " her durumda kullanmaksetImmediate() " tır .


1

Daha iyi anlaşılması için Döngü için ayrılmış dokümanlar bölümünü kontrol etmenizi öneririz . Oradan alınan bazı pasajlar:

Kullanıcılar açısından birbirine benzeyen iki çağrımız var, ancak adları kafa karıştırıcı.

  • process.nextTick () hemen aynı aşamada tetiklenir

  • setImmediate () yöntemi, aşağıdaki
    döngüde veya olay döngüsünün 'işaretinde' tetiklenir

Özünde, isimler değiştirilmelidir. process.nextTick (), setImmediate () öğesinden daha çabuk tetiklenir, ancak bu geçmişin değişmesi olası olmayan bir eserdir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.