सेट इमीडिएट बनाम नेक्स्ट


336

Node.js संस्करण 0.10 को आज जारी किया गया और पेश किया गया setImmediateएपीआई परिवर्तन प्रलेखन इसे प्रयोग जब पुनरावर्ती कर पता चलता है nextTickकॉल।

एमडीएन क्या कहता है, यह बहुत समान लगता है process.nextTick

मुझे कब उपयोग करना चाहिए nextTickऔर मुझे कब उपयोग करना चाहिए setImmediate?


20
ब्लॉग पर इस बदलाव के बारे में 5 पैराग्राफ हैं blog.nodejs.org/2013/03/11/node-v0-10-0-stable
mak

1
प्रदर्शन बेंचमार्क से ऐसा लगता है कि यह बड़ी गणना की nextTickतुलना में तेज़ है setImmediate

10
रिकॉर्ड के लिए, मैंने पहले उन पांच पैराग्राफों को पढ़ा और फिर भी इस सवाल पर समाप्त हो गया जब यह वास्तव में मेरे लिए कुछ भी स्पष्ट नहीं करता था। स्वीकृत उत्तर अधिक संक्षिप्त है और वास्तव में वर्णन setImmediateकरता है कि बेहतर विस्तार से क्या करता है।
Chev

मैंने अपने ब्लॉग में बहुत विस्तार से अंतर समझाया है ।
बजे

यह मामला है कि जी सी से पहले चला सकते है setImmediate, लेकिन उससे पहले नहीं nextTick?

जवाबों:


510

setImmediateयदि आप पहले से ही इवेंट कतार में जो भी I / O ईवेंट कॉलबैक हैं उसके पीछे फ़ंक्शन को पंक्तिबद्ध करना चाहते हैं, तो इसका उपयोग करें । process.nextTickफ़ंक्शन को प्रभावी रूप से पंक्तिबद्ध करने के लिए उपयोग करें इवेंट क्यू के सिर पर ताकि यह वर्तमान फ़ंक्शन के पूरा होने के तुरंत बाद निष्पादित हो।

तो ऐसे मामले में जहां आप एक लंबे समय से चल रहे ब्रेक-अप का उपयोग कर रहे हैं, सीपीयू-बाउंड जॉब को रिकर्सियन का उपयोग करते हुए, आप अब अगले पुनरावृत्ति को कतारबद्ध करने के setImmediateबजाय उपयोग करना चाहेंगे process.nextTickअन्यथा किसी भी I / O ईवेंट कॉलबैक को मौका नहीं मिलेगा। पुनरावृत्तियों के बीच चलाने के लिए।


86
कॉलबैक संसाधित हो गए ।nextTick को आम तौर पर निष्पादन के वर्तमान प्रवाह के अंत में बुलाया जाएगा, और इस प्रकार एक फ़ंक्शन को तुल्यकालिक रूप से कॉल करने में लगभग उतना ही तेज़ होगा। अनियंत्रित छोड़ दिया, यह घटना लूप को भूखा रखेगा, किसी भी I / O को होने से रोक देगा। setImmediates को बनाए गए क्रम में पंक्तिबद्ध किया जाता है, और लूप पुनरावृत्ति के अनुसार कतार से पॉपअप किया जाता है। यह process.nextTick से अलग है जो प्रक्रिया .axTickDepth कतार प्रति कॉलबैक को निष्पादित करेगा। यह सुनिश्चित करने के लिए कि आई / ओ को भूखा नहीं रखा जा रहा है, कतारबद्ध कॉलबैक फायरिंग करने के बाद, ईवेंट लूप में सेट होगा।
बेंजामिन ग्रुएनबाम

2
@UstamanSangat setImmediate IE10 + द्वारा समर्थित है, केवल अन्य सभी ब्राउज़र ज़िद्दी भविष्य के मानक को लागू करने से इनकार कर रहे हैं क्योंकि उन्हें Microsoft द्वारा पीटा जाना पसंद नहीं है। एफएफ / क्रोम में एक समान परिणाम प्राप्त करने के लिए, आप पोस्टमैसेज (अपनी खुद की खिड़की पर संदेश पोस्ट कर सकते हैं) का उपयोग कर सकते हैं। आप requestAnimationFrame का उपयोग करने पर विचार कर सकते हैं, खासकर यदि आपके अपडेट UI से संबंधित हैं। setTimeout (func, 0) प्रक्रिया की तरह काम नहीं करता है। बिल्कुल भी क्लिक करें।
fabspro

45
@fabspro "क्योंकि वे मेरे Microsoft को पीटना पसंद नहीं करते हैं" आपको कुछ के बारे में ध्वनि देता है। यह ज्यादातर है क्योंकि यह बहुत, बहुत नाम दिया है। अगर एक समय सेटिमिटेड फंक्शन होगा, तो कभी नहीं चलेगा, यह तुरंत है। फ़ंक्शन का नाम इसके ठीक विपरीत है जो यह करता है। अगलीटीक और सेटइमाउडेट को चारों ओर स्विच करना बेहतर होगा; setImmediate करंट स्टैक पूरा होने के तुरंत बाद निष्पादित होता है (I / O प्रतीक्षा करने से पहले) और NextTick अगले टिक के अंत में निष्पादित होता है (I / O प्रतीक्षा करने के बाद)। लेकिन फिर, यह एक हजार बार पहले ही कहा जा चुका है।
क्रेग एंड्रयूज

4
@fabspro लेकिन दुर्भाग्य से फंक्शन को नेक्स्टटीक कहा जाता है। nextTick "तुरंत" निष्पादित करता है जबकि setImmediate एक setTimeout / postMessage की तरह है।
राबर्ट

1
@CraigAndrews मैं इससे बचूंगा requestAnimationFrameक्योंकि यह हमेशा नहीं होता है (मैंने निश्चित रूप से यह देखा है, मुझे लगता है कि उदाहरण टैब वर्तमान टैब नहीं था) और इसे पेज पूरा होने से पहले बुलाया जा सकता है पेंटिंग (यानी ब्राउज़र अभी भी ड्राइंग में व्यस्त है)।
रोबोकट

68

चित्र के रूप में

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

निम्न आउटपुट देगा

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

मुझे उम्मीद है कि इससे अंतर को समझने में मदद मिल सकती है।

अपडेट किया गया:

process.nextTick()किसी अन्य I / O ईवेंट से पहले कॉलबैक स्थगित कर दिया गया है, जबकि setImmediate () के साथ, निष्पादन किसी भी I / O इवेंट के पीछे कतारबद्ध है जो पहले से ही कतार में है।

मारियो कैसिरो द्वारा Node.js डिजाइन पैटर्न , (शायद नोड के बारे में सबसे अच्छी किताब। js / js)


2
यह वाकई मददगार है धन्यवाद। मुझे लगता है कि कुछ समझने के लिए चित्र और उदाहरण सबसे तेज तरीका है।
जॉन जेम्स

1
मुझे लगता है कि उस सेटटाइमआउट () और सेटइमाउडेट () को इंगित करना महत्वपूर्ण है जब I / O चक्र के भीतर नहीं होता है, तो यह एक प्रक्रिया के प्रदर्शन के आधार पर आदेश गैर-नियतात्मक है। nodejs.org/en/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: तो, यह जवाब वास्तव में सटीक अंतर का जवाब नहीं देता है, लेकिन केवल एक उदाहरण जो विभिन्न संदर्भों में भिन्न हो सकता है
Actung

जैसा कि @Actung ने बताया है। यह निर्धारित करना बहुत महत्वपूर्ण है कि क्या सेटमीमाउट और सेटमीडिएट एक I / O चक्र के भीतर हैं या नहीं, परिणाम निर्धारित करने के लिए।
राजिका इमाल

50

मुझे लगता है कि मैं इसे काफी अच्छी तरह से समझा सकता हूं। चूंकि nextTickवर्तमान ऑपरेशन के अंत में कॉल किया जाता है, इसलिए इसे पुनरावर्ती रूप से कॉल करना इवेंट लूप को जारी रखने से रोक सकता है। setImmediateइवेंट लूप के चेक चरण में फायरिंग करके इसे हल करता है, जिससे ईवेंट लूप को सामान्य रूप से जारी रखा जा सकता है।

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

स्रोत: https://nodejs.org/en/docs/guides/event-loop-timers-and-nextroick/

ध्यान दें कि चेक चरण मतदान चरण के तुरंत बाद है। ऐसा इसलिए है क्योंकि चुनाव चरण और I / O कॉलबैक आपके कॉल setImmediateचलने की सबसे अधिक संभावना वाले स्थान हैं । तो आदर्श रूप से उन कॉलों में से अधिकांश वास्तव में बहुत तत्काल होंगे, बस उतने ही तत्काल नहीं, nextTickजो हर ऑपरेशन के बाद जांचे जाते हैं और तकनीकी रूप से इवेंट लूप के बाहर मौजूद होते हैं।

के बीच का अंतर का एक छोटा उदाहरण पर एक नज़र डालते हैं setImmediateऔर 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);

मान लें कि हमने अभी यह कार्यक्रम चलाया है और इवेंट लूप के पहले पुनरावृत्ति के माध्यम से आगे बढ़ रहे हैं। यह stepफ़ंक्शन में पुनरावृत्ति शून्य के साथ कॉल करेगा । यह तब दो हैंडलर, एक के लिए setImmediateऔर एक के लिए पंजीकृत करेगा process.nextTick। हम फिर से इस फ़ंक्शन को setImmediateहैंडलर से कॉल करते हैं जो अगले चेक चरण में चलेगा। nextTickहैंडलर वर्तमान कार्रवाई घटना पाश में दखल के अंत में चला जाएगा, तो भले ही यह दूसरा पंजीकृत किया गया था यह वास्तव में पहले चलेंगे।

यह आदेश समाप्त हो रहा है: nextTickवर्तमान ऑपरेशन समाप्त होते ही आग लग जाती है, अगला ईवेंट लूप शुरू होता है, सामान्य ईवेंट लूप चरण निष्पादित होते हैं, setImmediateआग लगाते हैं और पुन: stepप्रक्रिया को फिर से शुरू करने के लिए हमारे फ़ंक्शन को कॉल करते हैं। वर्तमान ऑपरेशन समाप्त होता है, nextTickआग, आदि।

उपरोक्त कोड का आउटपुट होगा:

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

अब अपने पुनरावर्ती कॉल को stepअपने nextTickहैंडलर में स्थानांतरित करने के बजाय ले जाएं 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);

अब जब हमने पुनरावर्ती कॉल को हैंडलर चीजों stepमें स्थानांतरित कर दिया है तो यह nextTickएक अलग क्रम में व्यवहार करेगा। ईवेंट लूप की हमारी पहली पुनरावृति stepएक setImmedaiteहैंडलर के साथ-साथ एक nextTickहैंडलर को पंजीकृत करने के लिए चलती है । वर्तमान ऑपरेशन के बाद हमारे nextTickहैंडलर की आग समाप्त हो जाती है जो पुन: कॉल करता है stepऔर दूसरे setImmediateहैंडलर के साथ-साथ दूसरे nextTickहैंडलर को पंजीकृत करता है । चूंकि एक nextTickहैंडलर करंट ऑपरेशन के बाद फायर करता है, इसलिए एक nextTickहैंडलर के भीतर एक nextTickहैंडलर का पंजीकरण करने से दूसरा हैंडलर मौजूदा हैंडलर ऑपरेशन के खत्म होने के तुरंत बाद चलेगा। nextTickसंचालकों फायरिंग रखेंगे, कभी जारी रखने से मौजूदा घटना पाश को रोकने। हम अपने सभी के माध्यम से प्राप्त करेंगेnextTickहैंडलर से पहले हम एक भी setImmediateहैंडलर आग देखते हैं ।

उपरोक्त कोड का आउटपुट समाप्त हो रहा है:

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

ध्यान दें कि हमने पुनरावर्ती कॉल को बाधित नहीं किया था और इसे 10 पुनरावृत्तियों के बाद निरस्त कर दिया था, फिर nextTickकॉल पुनरावृत्ति होते रहेंगे और कभी भी इवेंट लूप को अगले चरण तक जारी नहीं रखने देंगे। यह कैसे nextTickअवरुद्ध किया जा सकता है जब पुनरावर्ती उपयोग किया जाता है, जबकि setImmediateअगले ईवेंट लूप में आग लग जाएगी और एक दूसरे के setImmediateभीतर से किसी अन्य हैंडलर को सेट करने से वर्तमान ईवेंट लूप बाधित नहीं होगा, जिससे यह ईवेंट लूप के चरणों को सामान्य रूप से निष्पादित करना जारी रखेगा।

उम्मीद है की वो मदद करदे!

पुनश्च - मैं अन्य टिप्पणीकारों से सहमत हूं कि दो कार्यों के नामों को आसानी से अदला-बदली किया जा सकता है क्योंकि nextTickयह लगता है कि यह वर्तमान ईवेंट लूप के बजाय अगले ईवेंट लूप में आग लगाने वाला है, और वर्तमान लूप का अंत अधिक "तत्काल" है "अगले लूप की शुरुआत से। ओह ठीक है, यही हमें एक एपीआई परिपक्व के रूप में मिलता है और लोग मौजूदा इंटरफेस पर निर्भर करते हैं।


2
बहुत स्पष्ट वर्णन। मुझे लगता है कि इस उत्तर को और अधिक बढ़ाने की जरूरत है।
13

अच्छी तरह से समझाया (वाई)
धीरज शर्मा

प्रक्रिया के उपयोग के बारे में नोड की चेतावनी को दोहराना महत्वपूर्ण है ।nextTick। यदि आप नेक्स्ट क्विक्यू में बड़ी संख्या में कॉलबैक की गणना करते हैं, तो आप सुनिश्चित कर सकते हैं कि पोल चरण तक कभी न पहुँच पाने वाले ईवेंट लूप को भूखा रखा जाए। यही कारण है कि आपको आम तौर पर सेटमीमेड पसंद करना चाहिए।
faridcs

1
धन्यवाद, यह सबसे अच्छा स्पष्टीकरण था। नमूना कोड वास्तव में मदद की।
स्काईवॉक

@ कर्कवोक को खुशी है कि मैं मदद कर सका!
Chev

30

जवाब में टिप्पणियों में, यह स्पष्ट रूप से नहीं बताता है कि अगली बार मैक्रोसैमेंटिक्स से माइक्रोसैमेंटिक्स में स्थानांतरित हो गया।

नोड ०.१ से पहले (जब सेटइमाउडेट पेश किया गया था), नेक्स्ट कॉलबैक की शुरुआत में संचालित।

नोड 0.9 के बाद से, अगली टिक मौजूदा कॉलस्टैक के अंत में चल रही है, जबकि सेटमाइडेट अगले कॉलस्टैक की शुरुआत में है

बाहर की जाँच https://github.com/YuzuJS/setImmediate उपकरण और जानकारी के लिए


11

सरल शब्दों में, process.NextTick () इवेंट लूप के अगले टिक पर निष्पादित की जाएगी। हालाँकि, setImmediate, का मूल रूप से एक अलग चरण होता है जो यह सुनिश्चित करता है कि setImmediate () के तहत पंजीकृत कॉलबैक IO कॉलबैक और मतदान चरण के बाद ही कहा जाएगा।

कृपया अच्छी व्याख्या के लिए इस लिंक को देखें: https://medium.com/the-node-js-collection/what-you-should-know-to-really-understand-the-node-js-event-loop-and -its-मीट्रिक-c4907b19da4c

सरलीकृत घटना पाश घटनाओं


8

यहाँ कुछ बेहतरीन जवाब दिए गए हैं कि वे दोनों कैसे काम करते हैं।

बस एक प्रश्न जो उत्तर देता है, उसे जोड़ना:

मुझे कब उपयोग करना चाहिए nextTickऔर मुझे कब उपयोग करना चाहिए setImmediate?


हमेशा उपयोग करें setImmediate


Node.js घटना लूप, टाइमर, औरprocess.nextTick() दस्तावेज़ निम्नलिखित शामिल हैं:

हम डेवलपर्स setImmediate()को सभी मामलों में उपयोग करने की सलाह देते हैं क्योंकि यह कारण के लिए आसान है (और यह कोड की ओर जाता है जो पर्यावरण की एक विस्तृत विविधता के साथ संगत है, जैसे जेएस।)


इससे पहले डॉक्टर में यह चेतावनी दी गई है कि process.nextTick...

कुछ बुरी स्थितियां क्योंकि यह आपको पुनरावर्ती process.nextTick()कॉल करने से आपके I / O को "भूखा" करने की अनुमति देता है , जो ईवेंट लूप को पोल चरण तक पहुंचने से रोकता है ।

जैसा कि यह निकला, process.nextTickभूखा भी रह सकता है 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');
      })
    })
  })
})

दूसरी ओर, setImmediate"इस बारे में तर्क करना आसान है " और इस प्रकार के मुद्दों से बचा जाता है:

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

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

इसलिए जब तक विशिष्ट व्यवहार की आवश्यकता नहीं है process.nextTick, तब तक अनुशंसित दृष्टिकोण " सभी मामलों में उपयोग setImmediate()करना " है।


1

मैं आपको बेहतर समझ पाने के लिए लूप के लिए समर्पित डॉक्स अनुभाग की जांच करने की सलाह देता हूं । कुछ स्निपेट वहां से लिए गए:

हमारे पास दो कॉल हैं जो उपयोगकर्ताओं के संबंध में समान हैं, लेकिन उनके नाम भ्रामक हैं।

  • process.nextTick () एक ही चरण में तुरंत आग

  • setImmediate () निम्नलिखित पुनरावृत्ति या के 'टिक' पर आग
    ईवेंट लूप

संक्षेप में, नामों की अदला-बदली की जानी चाहिए। process.nextTick () setImmediate () की तुलना में अधिक तुरंत फायर करता है, लेकिन यह अतीत की एक कलाकृति है जो बदलने की संभावना नहीं है।

हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.