जावास्क्रिप्ट कब समकालिक है?


202

मैं इस धारणा के अधीन रहा हूं कि जावास्क्रिप्ट हमेशा अतुल्यकालिक थी। हालांकि, मैंने सीखा है कि ऐसी परिस्थितियां हैं जहां यह नहीं है (यानी डोम जोड़तोड़)। कहीं भी एक अच्छा संदर्भ है कि यह कब समकालिक होगा और कब अतुल्यकालिक होगा? क्या jQuery इस सब को प्रभावित करता है?


14
हमेशा अजाक्स के अपवाद के साथ।
defau1t

स्वीकृत उत्तर गलत है, और गलत है, कृपया इसे जांचें।
सूरज जैन

2
इवेंट लूप को समझने के लिए youtube.com/watch?v=8aGhZQkoFbQ भी उपयोगी था , और कैसे सिंक,
एसिंक्स के

1
@ defau1t यह गलत नहीं है, जावास्क्रिप्ट हमेशा सिंक्रोनस होता है, जब अजाक्स कॉल खत्म हो जाती है तो कॉलबैक कतार में समाप्त हो जाता है, यह जावा स्क्रिप्ट की सिंक्रोनस प्रकृति के लिए एक अपवाद कैसे है।
सूरज जैन

जवाबों:


281

जावास्क्रिप्ट हमेशा तुल्यकालिक और एकल-थ्रेडेड है। यदि आप किसी पृष्ठ पर जावास्क्रिप्ट ब्लॉक का कोड निष्पादित कर रहे हैं तो उस पृष्ठ पर कोई अन्य जावास्क्रिप्ट वर्तमान में निष्पादित नहीं किया जाएगा।

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

जावास्क्रिप्ट टाइमर इस तरह के कॉलबैक के साथ काम करते हैं।

जावास्क्रिप्ट को अतुल्यकालिक बताना शायद भ्रामक है। यह कहना अधिक सटीक है कि जावास्क्रिप्ट विभिन्न कॉलबैक तंत्रों के साथ समकालिक और थ्रेडेड है।

jQuery के पास उन्हें async: falseवैकल्पिक रूप से ( विकल्प के साथ ) बनाने के लिए अजाक्स कॉल पर एक विकल्प है । शुरुआती लोगों को इसे गलत तरीके से इस्तेमाल करने के लिए लुभाया जा सकता है क्योंकि यह एक अधिक पारंपरिक प्रोग्रामिंग मॉडल की अनुमति देता है जो किसी को अधिक उपयोग में लाया जा सकता है। कारण यह समस्याग्रस्त है कि यह विकल्प पृष्ठ पर सभी जावास्क्रिप्ट को तब तक अवरुद्ध करेगा , जब तक कि यह समाप्त नहीं हो जाता है, जिसमें सभी ईवेंट हैंडलर और टाइमर शामिल हैं।


31
क्षमा करें, मुझे यह कथन बिलकुल समझ में नहीं आया "जब तक कॉल वापस नहीं आती (सफलतापूर्वक या त्रुटि में) कोड निष्पादित करना बंद कर देगा"। क्या आप विस्तृत कर सकते हैं जब आप यह भी कहते हैं कि "यह कोई अन्य कोड जो चल रहा है उसे बाधित नहीं करेगा" तो यह कथन कैसे सच हो सकता है; क्या आप पहले बयान में केवल कॉलबैक कोड के बारे में बात कर रहे हैं? कृपया मुझे ज्ञान दो।
कृष्ण पक्ष

2
Nettuts का एक ट्यूटोरियल है जो यहाँ async की मूल बातें समझाने में बहुत अच्छा है: net.tutsplus.com/tutorials/javascript-ajax/…
RobW

26
@ क्लेटस कथन "कॉल रिटर्न होने तक कोड निष्पादित करना बंद कर देगा" सुधार की आवश्यकता है क्योंकि निष्पादन बंद नहीं होता है। कोड निष्पादन जारी रह सकता है। अन्यथा, इसका मतलब होगा कि कॉल सिंक्रोनस है।
एच.एस.

1
मुझे वह कथन भी समझ नहीं आया।
टोरी

12
यह उत्तर अविश्वसनीय रूप से भ्रामक और भ्रमित करने वाला है। कृपया इसके बजाय CMS 'या फ़राज़ अहमद का जवाब देखें।
आयन जूल

214

जावास्क्रिप्ट एकल थ्रेडेड है और एक तुल्यकालिक निष्पादन मॉडल है। सिंगल थ्रेडेड का मतलब है कि एक समय में एक कमांड को निष्पादित किया जा रहा है। सिंक्रोनस का मतलब एक समय में होता है यानी कोड की एक लाइन कोड के प्रकट होने के समय पर निष्पादित की जाती है। तो जावास्क्रिप्ट में एक समय में एक बात हो रही है।

निष्पादन प्रसंग

जावास्क्रिप्ट इंजन ब्राउज़र में अन्य इंजनों के साथ इंटरैक्ट करता है। जावास्क्रिप्ट निष्पादन स्टैक में नीचे की ओर वैश्विक संदर्भ होता है और फिर जब हम फ़ंक्शन करते हैं तो जावास्क्रिप्ट इंजन संबंधित कार्यों के लिए नए निष्पादन संदर्भ बनाता है। जब फंक्शन फंक्शन से बाहर निकलता है, तो इसका निष्पादन संदर्भ स्टैक से पॉप अप हो जाता है, और फिर अगला निष्पादन संदर्भ पॉप अप और इसी तरह ...

उदाहरण के लिए

function abc()
{
   console.log('abc');
}


function xyz()
{
   abc()
   console.log('xyz');
}
var one = 1;
xyz();

उपरोक्त कोड में एक वैश्विक निष्पादन संदर्भ बनाया जाएगा और इस संदर्भ में var oneसंग्रहीत किया जाएगा और इसका मूल्य 1 होगा ... जब xyz () आह्वान किया जाता है तो एक नया निष्पादन संदर्भ बनाया जाएगा और अगर हमने किसी चर को परिभाषित किया था xyz फ़ंक्शन में उन चर xyz () के निष्पादन संदर्भ में संग्रहीत किए जाएंगे। Xyz फ़ंक्शन में हम abc () और उसके बाद abc () निष्पादन संदर्भ बनाया जाता है और निष्पादन स्टैक पर डाल दिया जाता है ... अब जब abc () अपना संदर्भ समाप्त करता है तो स्टैक से पॉप किया जाता है, फिर xyz () संदर्भ पॉप हो जाता है स्टैक और फिर वैश्विक संदर्भ पॉप हो जाएगा ...

अब अतुल्यकालिक कॉलबैक के बारे में; अतुल्यकालिक का अर्थ है एक समय में एक से अधिक।

निष्पादन स्टैक की तरह ही इवेंट क्यू है । जब हम जावास्क्रिप्ट इंजन में किसी घटना के बारे में सूचित होना चाहते हैं तो हम उस घटना को सुन सकते हैं, और उस घटना को कतार में रखा जाता है। उदाहरण के लिए एक अजाक्स अनुरोध घटना, या HTTP अनुरोध घटना।

जब भी निष्पादन स्टैक खाली होता है, जैसा कि ऊपर दिए गए कोड उदाहरण में दिखाया गया है, तो जावास्क्रिप्ट इंजन समय-समय पर घटना की कतार को देखता है और देखता है कि क्या किसी घटना के बारे में अधिसूचित किया जाना है। उदाहरण के लिए कतार में दो कार्यक्रम, एक अजाक्स अनुरोध और एक HTTP अनुरोध थे। यह भी देखने के लिए लगता है कि क्या कोई फ़ंक्शन है जिसे उस इवेंट ट्रिगर पर चलाने की आवश्यकता है ... इसलिए जावास्क्रिप्ट इंजन को इस घटना के बारे में सूचित किया जाता है और उस घटना को निष्पादित करने के लिए संबंधित फ़ंक्शन को जानता है ... इसलिए जावास्क्रिप्ट इंजन को आमंत्रित करता है हैंडलर फ़ंक्शन, उदाहरण के मामले में, जैसे अजाक्सहैंडलर () को हमेशा के लिए लागू किया जाएगा और जब किसी फ़ंक्शन को लागू किया जाता है, तो इसका निष्पादन संदर्भ निष्पादन के संदर्भ में रखा जाता है और अब फ़ंक्शन निष्पादन समाप्त हो जाता है और इवेंट ajax अनुरोध भी इवेंट कतार से हटा दिया जाता है ... जब अजाक्सहैंडलर () खत्म हो जाता है तो निष्पादन स्टैक खाली हो जाता है इसलिए इंजन फिर से इवेंट कतार में दिखता है और HTTP अनुरोध के ईवेंट हैंडलर फ़ंक्शन को चलाता है जो कतार में आगे था। यह याद रखना महत्वपूर्ण है कि ईवेंट कतार तभी संसाधित होती है जब निष्पादन स्टैक खाली होता है।

उदाहरण के लिए जावास्क्रिप्ट इंजन द्वारा निष्पादन स्टैक और ईवेंट क्यू हैंडलिंग को समझाते हुए नीचे दिए गए कोड को देखें।

function waitfunction() {
    var a = 5000 + new Date().getTime();
    while (new Date() < a){}
    console.log('waitfunction() context will be popped after this line');
}

function clickHandler() {
    console.log('click event handler...');   
}

document.addEventListener('click', clickHandler);


waitfunction(); //a new context for this function is created and placed on the execution stack
console.log('global context will be popped after this line');

तथा

<html>
    <head>

    </head>
    <body>

        <script src="program.js"></script>
    </body>
</html>

अब वेबपेज चलाएं और पेज पर क्लिक करें, और कंसोल पर आउटपुट देखें। आउटपुट होगा

waitfunction() context will be popped after this line
global context will be emptied after this line
click event handler...

जावास्क्रिप्ट इंजन कोड को समान रूप से चला रहा है जैसा कि निष्पादन संदर्भ भाग में समझाया गया है, ब्राउज़र असमान रूप से घटना कतार में चीजों को डाल रहा है। तो जिन कार्यों को पूरा करने में बहुत लंबा समय लगता है, वे ईवेंट हैंडलिंग को बाधित कर सकते हैं। ब्राउज़र जैसी घटनाओं में होने वाली चीजें जावास्क्रिप्ट द्वारा इस तरह से नियंत्रित की जाती हैं, अगर कोई श्रोता चलाने वाला होता है, तो निष्पादन स्टैक खाली होने पर इंजन इसे चलाएगा। और घटनाओं को उनके द्वारा होने वाले क्रम में संसाधित किया जाता है, इसलिए अतुल्यकालिक भाग इंजन के बाहर क्या हो रहा है, अर्थात जब वे बाहरी घटनाएँ होती हैं तो इंजन को क्या करना चाहिए।

इसलिए जावास्क्रिप्ट हमेशा तुल्यकालिक है।


16
यह उत्तर बहुत स्पष्ट है, इसे अधिक उत्थान मिलना चाहिए।
रानू

7
निश्चित रूप से जावास्क्रिप्ट के अतुल्यकालिक व्यवहार के लिए सबसे अच्छा स्पष्टीकरण जो मैंने पढ़ा है।
चार्ल्स जैमेट

1
निष्पादन संदर्भ और कतार की अच्छी व्याख्या।
दिव्यांशु मैथानी

1
बेशक इसके लिए आपको निष्पादन संदर्भ स्टैक के बारे में थोड़ा सा पढ़ना होगा, और केवल इसके अतिरिक्त होने के कारण खाली होना और घटना की कतार मुझे अंततः महसूस कराती है जैसे मैं जावा स्क्रिप्ट एक्सीलेंस को सामान्य रूप से समझता हूं। क्या बुरा है मुझे लगता है कि यह केवल पढ़ने का एक पृष्ठ लेता है फिर भी मुझे शायद ही कहीं मिलता है। तो क्यों कोई इसे बस कहता है? या तो वे नहीं जानते या क्या? लेकिन मुझे लगता है कि अगर एक js ट्यूटोरियल होता तो यह मुझे बहुत समय बचा सकता था। >: |
मार्शल शिल्प

2
सही व्याख्या!
तुलसी

100

जावास्क्रिप्ट एकल-थ्रेडेड है, और हर समय जब आप एक सामान्य तुल्यकालिक कोड-प्रवाह निष्पादन पर काम करते हैं।

एसिंक्रोनस व्यवहार के अच्छे उदाहरण जो जावास्क्रिप्ट हो सकते हैं वे घटनाएँ हैं (उपयोगकर्ता इंटरैक्शन, अजाक्स अनुरोध परिणाम, आदि) और टाइमर, मूल रूप से क्रियाएं जो किसी भी समय हो सकती हैं।

मैं आपको निम्नलिखित लेख को देखने की सलाह दूंगा:

यह लेख आपको जावास्क्रिप्ट के एकल-थ्रेडेड स्वरूप को समझने में मदद करेगा और टाइमर आंतरिक रूप से कैसे काम करते हैं और अतुल्यकालिक जावास्क्रिप्ट निष्पादन कैसे काम करते हैं।

async


स्वीकृत उत्तर के गलत होने पर क्या हम उस मामले में कुछ कर सकते हैं? /
सूरज जैन

8

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

जिस तरह से इसके कोड को निष्पादित किया गया है, उसमें जेएस समकालिक है। प्रत्येक लाइन पूरी होने से पहले ही लाइन के बाद चलती है और यदि वह लाइन पूर्ण एक्ट के बाद किसी फ़ंक्शन को कॉल करती है ...

भ्रम का मुख्य बिंदु इस तथ्य से उत्पन्न होता है कि आपका ब्राउज़र जेएस को किसी भी समय अधिक कोड बहाने में सक्षम है (आप कंसोल से एक पृष्ठ पर अधिक जेएस कोड को कैसे उत्तेजित कर सकते हैं इसके बारे में अनुकरण करें)। एक उदाहरण के रूप में जेएस के पास कॉलबैक फ़ंक्शन हैं जिनका उद्देश्य जेएस को अतुल्यकालिक रूप से अनुमति देना है ताकि जेएस फ़ंक्शन के निष्पादन के इंतजार के दौरान जेएस के आगे के हिस्से चल सकें (IE GETकॉल) एक जवाब वापस करने के लिए, जेएस तब तक चलता रहेगा। ब्राउज़र के पास इस बात का जवाब होता है कि इवेंट लूप (ब्राउज़र) जेएस कोड को निष्पादित करेगा जो कॉलबैक फ़ंक्शन को कॉल करता है।

चूँकि ईवेंट लूप (ब्राउज़र) अधिक जेएस को इनपुट कर सकता है जो किसी भी बिंदु पर उस अर्थ में निष्पादित किया जाएगा जेएस अतुल्यकालिक है (जेएस कोड इनपुट करने के लिए एक ब्राउज़र का कारण होगा प्राथमिक चीजें टाइमआउट, कॉलबैक और ईवेंट हैं)

मुझे उम्मीद है कि यह स्पष्ट है कि किसी के लिए उपयोगी हो।


4

परिभाषा

शब्द "एसिंक्रोनस" का उपयोग थोड़े अलग अर्थों में किया जा सकता है, जिसके परिणामस्वरूप प्रतीत होता है कि परस्पर विरोधी उत्तर यहां हैं, जबकि वे वास्तव में नहीं हैं। एसिंक्रोनसी पर विकिपीडिया की यह परिभाषा है:

अतुल्यकालिक, कंप्यूटर प्रोग्रामिंग में, मुख्य कार्यक्रम के प्रवाह से स्वतंत्र घटनाओं और ऐसी घटनाओं से निपटने के तरीकों की घटना को संदर्भित करता है। ये "बाहरी" घटनाएं हो सकती हैं जैसे कि संकेतों के आगमन, या कार्यक्रम द्वारा उकसाए गए कार्यक्रम जो कार्यक्रम के निष्पादन के साथ समवर्ती रूप से होते हैं, कार्यक्रम के परिणामों के लिए प्रतीक्षा करने के लिए अवरुद्ध किए बिना।

गैर-जावास्क्रिप्ट कोड जावास्क्रिप्ट के कुछ घटनाओं की कतार के लिए इस तरह के "बाहर" घटनाओं को कतारबद्ध कर सकता है। लेकिन यह जहाँ तक जाता है।

कोई पूर्वधारणा नहीं

आपकी स्क्रिप्ट में कुछ अन्य जावास्क्रिप्ट कोड निष्पादित करने के लिए जावास्क्रिप्ट कोड चलाने का कोई बाहरी व्यवधान नहीं है । जावास्क्रिप्ट के टुकड़ों को एक के बाद एक निष्पादित किया जाता है, और आदेश प्रत्येक घटना कतार में घटनाओं के क्रम और उन कतारों की प्राथमिकता से निर्धारित होता है।

उदाहरण के लिए, आप पूरी तरह से सुनिश्चित हो सकते हैं कि कोई भी जावास्क्रिप्ट (उसी स्क्रिप्ट में) कभी भी निष्पादित नहीं होगा, जबकि निम्नलिखित कोड कोड निष्पादित होता है:

let a = [1, 4, 15, 7, 2];
let sum = 0;
for (let i = 0; i < a.length; i++) {
    sum += a[i];
}

दूसरे शब्दों में, जावास्क्रिप्ट में कोई पूर्व सूचना नहीं है । जो कुछ भी घटना कतारों में हो सकता है, उन घटनाओं के प्रसंस्करण को तब तक इंतजार करना होगा जब तक कि इस तरह का कोड पूरा नहीं हो जाता। EcmaScript विनिर्देश धारा 8.4 नौकरियों और नौकरियों कतार में कहते हैं :

किसी कार्य का निष्पादन केवल तभी शुरू किया जा सकता है जब कोई निष्पादन निष्पादन संदर्भ न हो और निष्पादन संदर्भ स्टैक खाली हो।

अतुल्यकालिक के उदाहरण

जैसा कि अन्य लोग पहले ही लिख चुके हैं, ऐसी कई स्थितियाँ हैं जहाँ जावास्क्रिप्ट में अतुल्यकालिक खेल आता है, और इसमें हमेशा एक घटना कतार शामिल होती है, जिसके परिणामस्वरूप केवल जावास्क्रिप्ट निष्पादन हो सकता है जब कोई अन्य जावास्क्रिप्ट कोड निष्पादित नहीं होता है:

  • setTimeout(): समय समाप्त हो जाने पर एजेंट (जैसे ब्राउज़र) ईवेंट कतार में एक घटना डाल देगा। समय की निगरानी और घटना को कतार में रखना गैर-जावास्क्रिप्ट कोड द्वारा होता है, और इसलिए आप कल्पना कर सकते हैं कि यह कुछ जावास्क्रिप्ट कोड के संभावित निष्पादन के समानांतर होता है। लेकिन कॉलबैक प्रदान करने के लिए setTimeoutकेवल तभी क्रियान्वित किया जा सकता है जब वर्तमान में जावास्क्रिप्ट कोड निष्पादित हो रहा है और पूरा हो गया है और उपयुक्त ईवेंट कतार पढ़ी जा रही है।

  • fetch(): एजेंट एक HTTP अनुरोध करने और किसी भी आने वाली प्रतिक्रिया के लिए निगरानी करने के लिए OS फ़ंक्शन का उपयोग करेगा। फिर, यह गैर-जावास्क्रिप्ट कार्य कुछ जावास्क्रिप्ट कोड के समानांतर चल सकता है जो अभी भी निष्पादित हो रहा है। लेकिन वादा समाधान प्रक्रिया, जो कि लौटाए गए वादे को हल करेगी fetch(), केवल तभी निष्पादित हो सकती है जब वर्तमान में निष्पादित जावास्क्रिप्ट पूरा होने के लिए दौड़ा हो।

  • requestAnimationFrame(): ब्राउज़र का रेंडरिंग इंजन (नॉन-जावास्क्रिप्ट) एक घटना को जावास्क्रिप्ट कतार में रखेगा जब वह पेंट ऑपरेशन करने के लिए तैयार होगा। जब जावास्क्रिप्ट ईवेंट संसाधित होता है तो कॉलबैक फ़ंक्शन निष्पादित होता है।

  • queueMicrotask(): तुरंत एक घटना को माइक्रोटस्क कतार में रखता है। कॉल स्टैक खाली होने पर कॉलबैक निष्पादित किया जाएगा और उस ईवेंट का उपभोग किया जाएगा।

कई और उदाहरण हैं, लेकिन ये सभी कार्य मेजबान पर्यावरण द्वारा प्रदान किए जाते हैं, कोर एक्मास्क्रिप्ट द्वारा नहीं। कोर एक्मास्क्रिप्ट के साथ आप एक घटना को एक वादा नौकरी की कतार में रख सकते हैं Promise.resolve()

भाषा का निर्माण

ECMAScript जैसे asynchrony पैटर्न का समर्थन करने के कई भाषा निर्माणों, प्रदान करता है yield, async, await। लेकिन कोई गलती न होने दें: कोई जावास्क्रिप्ट कोड किसी बाहरी घटना से बाधित नहीं होगा । "रुकावट" कि yieldऔर awaitप्रदान करने के लिए लग रहे हैं, बस एक नियंत्रित, एक समारोह कॉल से लौटने और बाद में इसके निष्पादन संदर्भ बहाल करने की पूर्वनिर्धारित तरीका है या तो जे एस कोड (के मामले में yield), या घटना कतार (के मामले में await)।

डोम इवेंट हैंडलिंग

जब जावास्क्रिप्ट कोड DOM API को एक्सेस करता है, तो यह कुछ मामलों में DOM API को एक या अधिक सिंक्रोनस नोटिफ़िकेशन को ट्रिगर कर सकता है। और अगर आपके कोड में कोई इवेंट हैंडलर है जो उसे सुन रहा है, तो उसे कॉल किया जाएगा।

यह पूर्व-खाली कंसीडर के रूप में सामने आ सकता है, लेकिन ऐसा नहीं है: एक बार जब आपका ईवेंट हैंडलर (रिटर्न) वापस आ जाता है, तो DOM API भी अंततः वापस आ जाएगा, और मूल जावास्क्रिप्ट कोड जारी रहेगा।

अन्य मामलों में DOM API केवल किसी ईवेंट को उचित ईवेंट कतार में भेज देगा, और कॉल स्टैक खाली करने के बाद JavaScript इसे उठा लेगी।

सिंक्रोनस और एसिंक्रोनस इवेंट देखें


0

सभी मामलों पर समकालिक है।

ब्लॉकिंग थ्रेड का उदाहरण Promises:

  const test = () => new Promise((result, reject) => {
    const time = new Date().getTime() + (3 * 1000);

    console.info('Test start...');

    while (new Date().getTime() < time) {
      // Waiting...
    }

    console.info('Test finish...');
  });

  test()
    .then(() => console.info('Then'))
    .finally(() => console.info('Finally'));

  console.info('Finish!');

उत्पादन होगा:

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