मुझे इवेंट-आधारित प्रोग्रामिंग का उपयोग कब करना चाहिए?


65

मैं कॉलबैक से गुजर रहा हूं या अपने कार्यक्रमों में अन्य फ़ंक्शन से कार्यों को ट्रिगर कर रहा हूं ताकि एक बार कार्य पूरा हो जाए। जब कुछ खत्म हो जाता है, तो मैं सीधे फ़ंक्शन को ट्रिगर करता हूं:

var ground = 'clean';

function shovelSnow(){
    console.log("Cleaning Snow");
    ground = 'clean';
}

function makeItSnow(){
    console.log("It's snowing");
    ground = 'snowy';
    shovelSnow();
}

लेकिन मैंने प्रोग्रामिंग में कई अलग-अलग रणनीतियों के बारे में पढ़ा है, और एक जिसे मैं शक्तिशाली होना समझता हूं, लेकिन अभी तक अभ्यास नहीं किया है, घटना-आधारित है (मुझे लगता है कि मैंने जिस विधि के बारे में पढ़ा था उसे "पब-उप" कहा गया था ):

var ground = 'clean';

function shovelSnow(){
    console.log("Cleaning Snow");
    ground = 'clean';
}

function makeItSnow(){
    console.log("It's snowing");
    ground = 'snowy';
    $(document).trigger('snow');
}

$(document).bind('snow', shovelSnow);

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


2
एक तरफ के रूप में, आप बस का उपयोग कर सकते हैं $(document).bind('snow', shovelShow)। किसी अनाम फ़ंक्शन में इसे लपेटने की आवश्यकता नहीं है।
कार्ल बेवलफेल्ट

4
आपको "प्रतिक्रियाशील प्रोग्रामिंग" के बारे में जानने में भी दिलचस्पी हो सकती है, जिसमें इवेंट-संचालित प्रोग्रामिंग के साथ बहुत कुछ है।
एरिक लिपर्ट

जवाबों:


75

एक घटना एक अधिसूचना है जो हाल के समय से एक घटना का वर्णन करती है।

इवेंट-संचालित सिस्टम का एक विशिष्ट कार्यान्वयन एक इवेंट डिस्पैचर और हैंडलर फ़ंक्शन (या सब्सक्राइबर ) का उपयोग करता है। डिस्पैचर घटनाओं (jQuery के bind), और अपने ग्राहकों triggerको jQuery में एक घटना प्रकाशित करने के लिए एक विधि के लिए तार संचालकों के लिए एक एपीआई प्रदान करता है । जब आप IO या UI घटनाओं के बारे में बात कर रहे हैं, तो आमतौर पर एक इवेंट लूप भी होता है , जो माउस-क्लिक जैसी नई घटनाओं का पता लगाता है और उन्हें डिस्पैचर में भेजता है। जेएस-भूमि में, डिस्पैचर और इवेंट लूप ब्राउज़र द्वारा प्रदान किए जाते हैं।

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

आपका उदाहरण, जिसमें आप किसी फ़ंक्शन को सीधे कॉल करने के बजाय अपने कोड में एक घटना बढ़ाते हैं, कुछ और दिलचस्प ट्रेडऑफ़ हैं, जिनकी मैं नीचे चर्चा करूंगा। मुख्य अंतर यह है कि किसी घटना के प्रकाशक ( makeItSnow) कॉल के रिसीवर को निर्दिष्ट नहीं करता है; वह कहीं और तार दिया गया है ( bindआपके उदाहरण में कॉल में)। इसे अग्नि-विस्मरण कहा जाता है : यह makeItSnowघोषणा करता है कि दुनिया में बर्फबारी हो रही है, लेकिन यह परवाह नहीं करता है कि कौन क्या सुन रहा है, आगे क्या होता है, या जब ऐसा होता है - यह बस संदेश प्रसारित करता है और अपने हाथों से धूल जाता है।


तो घटना-संचालित दृष्टिकोण रिसीवर से संदेश के प्रेषक को डिकॉउंड करता है। इससे एक फायदा यह होता है कि आप दिए गए इवेंट में कई हैंडलर लगा सकते हैं। gritRoadsमौजूदा shovelSnowहैंडलर को प्रभावित किए बिना आप अपने स्नो इवेंट में एक समारोह में शामिल हो सकते हैं । आपके आवेदन के वायर्ड होने के तरीके में आपके पास लचीलापन है; एक व्यवहार को बंद करने के लिए आपको bindकोड को व्यवहार के सभी उदाहरणों को खोजने के लिए कोड के माध्यम से जाने के बजाय कॉल को हटाने की आवश्यकता है ।

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

पूर्ण प्रकटीकरण: ब्रिडल को हडले में विकसित किया गया है, जहां मैं काम करता हूं।

रिसीवर से एक घटना के प्रेषक को डिकूप करने का तीसरा लाभ यह है कि जब आप घटना को संभालते हैं तो यह आपको लचीलापन देता है । आप प्रत्येक प्रकार के ईवेंट को अपने स्वयं के थ्रेड पर संसाधित कर सकते हैं (यदि आपका ईवेंट डिस्पैचर इसका समर्थन करता है), या आप रैबिटएमक्यू जैसे संदेश ब्रोकर पर उठाए गए ईवेंट डाल सकते हैं और उन्हें एक एसिंक्रोनस प्रक्रिया के साथ संभाल सकते हैं या रात भर में उन्हें संसाधित कर सकते हैं। घटना का रिसीवर एक अलग प्रक्रिया में या एक अलग मशीन पर हो सकता है। आपको कोड बदलने की ज़रूरत नहीं है जो ऐसा करने के लिए घटना को उठाता है! यह "microservice" आर्किटेक्चर के पीछे बड़ा आइडिया है: ऑटोनोमस सेवाएं ईवेंट का उपयोग करके संचार करती हैं, साथ ही संदेशवाहक को एप्लिकेशन की रीढ़ के रूप में संदेश देती हैं।

ईवेंट-चालित शैली के एक अलग रूप से भिन्न उदाहरण के लिए, डोमेन-संचालित डिज़ाइन को देखें, जहाँ एग्रीगेट को अलग रखने में सहायता के लिए डोमेन ईवेंट का उपयोग किया जाता है। उदाहरण के लिए, एक ऑनलाइन स्टोर पर विचार करें जो आपके खरीद इतिहास के आधार पर उत्पादों की सिफारिश करता है। एक Customerअपनी खरीद इतिहास को अद्यतन किया है जब एक की जरूरत ShoppingCartके लिए भुगतान किया जाता है। ShoppingCartकुल सूचित कर सकते हैं Customerएक बढ़ाकर CheckoutCompletedघटना; Customerघटना के जवाब में एक अलग लेन-देन में अपडेट कर दिया जाएगा।


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

एक और नुकसान यह है कि घटनाओं को फिर से भरना मुश्किल है। यदि आपको किसी घटना के प्रारूप को बदलने की आवश्यकता है तो आपको सभी रिसीवरों को भी बदलना होगा। यह तब समाप्त हो जाता है जब किसी ईवेंट के ग्राहक विभिन्न मशीनों पर होते हैं, क्योंकि अब आपको सॉफ़्टवेयर रिलीज़ को सिंक्रनाइज़ करने की आवश्यकता है!

कुछ परिस्थितियों में, प्रदर्शन एक चिंता का विषय हो सकता है। संदेश को संसाधित करते समय, डिस्पैचर को निम्न करना होता है:

  1. कुछ डेटा संरचना में सही हैंडलर देखें।
  2. प्रत्येक हैंडलर के लिए एक संदेश प्रसंस्करण पाइपलाइन बनाएँ। इसमें मेमोरी आवंटन का एक समूह शामिल हो सकता है।
  3. गतिशील रूप से हैंडलर को बुलाओ (संभवत: प्रतिबिंब का उपयोग करते हुए अगर भाषा को इसकी आवश्यकता है)।

यह निश्चित रूप से एक नियमित फ़ंक्शन कॉल की तुलना में धीमा है, जिसमें केवल स्टैक पर एक नया फ्रेम पुश करना शामिल है। हालाँकि, लचीलापन जो एक ईवेंट-चालित आर्किटेक्चर आपको पसंद करता है, धीमी कोड को अलग करना और अनुकूलित करना बहुत आसान बनाता है। एक अतुल्यकालिक प्रोसेसर के लिए काम प्रस्तुत करने की क्षमता होने के नाते यहां एक बड़ी जीत है, क्योंकि यह आपको तुरंत अनुरोध करने की अनुमति देता है जबकि पृष्ठभूमि में कड़ी मेहनत से निपटा जाता है। किसी भी स्थिति में, यदि आप स्क्रीन पर DB या ड्राइंग सामान के साथ बातचीत कर रहे हैं, तो IO की लागत किसी संदेश को संसाधित करने की लागतों को पूरी तरह से स्वाहा कर देगी। यह समय से पहले अनुकूलन से बचने का मामला है।


संक्षेप में, घटनाओं में शिथिल युग्मित सॉफ़्टवेयर बनाने का एक शानदार तरीका है, लेकिन वे लागत के बिना नहीं हैं। उदाहरण के लिए, यह गलत होगा कि आपके एप्लिकेशन में प्रत्येक फ़ंक्शन कॉल को किसी ईवेंट के साथ बदल दिया जाए। सार्थक स्थापत्य विभाजन बनाने के लिए घटनाओं का उपयोग करें।


2
यह उत्तर 5377 के उत्तर के समान है जिसे मैंने सही के रूप में चुना था; मैं इसे चुनने के लिए अपना चयन बदल रहा हूं क्योंकि यह आगे विस्तृत है।
विजीयोनरी

1
क्या घटना-संचालित कोड का एक महत्वपूर्ण नुकसान है? ऐसा लगता है कि यह हो सकता है, लेकिन मुझे पता नहीं है।
raptortech97

1
@ raptortech97 यह निश्चित रूप से हो सकता है। कोड के लिए जिसे विशेष रूप से तेज़ होने की आवश्यकता है, आप शायद आंतरिक लूप में घटनाओं को भेजने से बचना चाहेंगे; सौभाग्य से, ऐसी स्थितियों में इसकी आम तौर पर अच्छी तरह से परिभाषित किया जाता है कि आपको क्या करने की आवश्यकता है, इसलिए आपको अतिरिक्त लचीले रूप से घटनाओं (या प्रकाशित / सदस्यता या पर्यवेक्षकों की आवश्यकता नहीं है, जो कि विभिन्न शब्दावली के साथ समान तंत्र हैं)।
जूल्स

1
यह भी ध्यान दें कि अभिनेता मॉडल के चारों ओर निर्मित कुछ भाषाएँ (जैसे एर्लांग) हैं जहाँ सब कुछ संदेश (घटनाएँ) है। इस मामले में कंपाइलर यह तय कर सकता है कि संदेश / घटनाओं को सीधे फ़ंक्शन कॉल या संचार के रूप में लागू करना है या नहीं।
ब्रेंडन

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

25

इवेंट-आधारित प्रोग्रामिंग का उपयोग तब किया जाता है जब प्रोग्राम उन घटनाओं के अनुक्रम को नियंत्रित नहीं करता है जो यह प्रदर्शन करता है। इसके बजाय, प्रोग्राम प्रवाह एक बाहरी प्रक्रिया जैसे कि एक उपयोगकर्ता (जैसे जीयूआई), एक अन्य सिस्टम (जैसे क्लाइंट / सर्वर), या एक अन्य प्रक्रिया (जैसे आरपीसी) द्वारा निर्देशित होता है।

उदाहरण के लिए, एक बैच प्रोसेसिंग स्क्रिप्ट को पता है कि उसे ऐसा करने की आवश्यकता है ताकि वह इसे कर सके। यह है नहीं घटना के आधार पर।

एक वर्ड प्रोसेसर वहां बैठता है और उपयोगकर्ता के टाइपिंग शुरू होने का इंतजार करता है। कीपन्स ऐसी घटनाएं हैं जो आंतरिक दस्तावेज़ बफर को अपडेट करने के लिए कार्यक्षमता को ट्रिगर करती हैं। प्रोग्राम यह नहीं जान सकता कि आप क्या लिखना चाहते हैं, इसलिए इसे इवेंट-संचालित होना चाहिए।

अधिकांश GUI कार्यक्रम ईवेंट-चालित होते हैं क्योंकि वे उपयोगकर्ता इंटरैक्शन के आसपास बनाए जाते हैं। हालाँकि, ईवेंट-आधारित कार्यक्रम GUIs तक सीमित नहीं हैं, जो कि ज्यादातर लोगों के लिए सबसे परिचित उदाहरण है। वेब सर्वर एक समान मुहावरे को जोड़ने और उसका अनुसरण करने के लिए ग्राहकों की प्रतीक्षा करते हैं। आपके कंप्यूटर पर पृष्ठभूमि प्रक्रियाएँ घटनाओं पर भी प्रतिक्रिया दे सकती हैं। उदाहरण के लिए, ऑन-डिमांड वायरस स्कैनर एक नई बनाई या अपडेट की गई फ़ाइल के बारे में ओएस से एक घटना प्राप्त कर सकता है, फिर वायरस के लिए उस फ़ाइल को स्कैन करें।


18

ईवेंट-आधारित एप्लिकेशन में इवेंट श्रोताओं की अवधारणा आपको और भी अधिक लूज़ली युग्मित एप्लिकेशन लिखने की क्षमता प्रदान करेगी ।

उदाहरण के लिए, एक तृतीय-पक्ष मॉड्यूल या प्लग-इन डेटाबेस से एक रिकॉर्ड को हटा सकता है और फिर receordDeletedघटना को ट्रिगर कर सकता है और बाकी श्रोताओं को अपना काम करने के लिए छोड़ सकता है। सब कुछ ठीक चलेगा, भले ही ट्रिगर मॉड्यूल को यह भी पता न हो कि इस विशेष घटना के लिए कौन सुन रहा है या आगे क्या होना चाहिए।


6

एक साधारण सादृश्य जो मैं जोड़ना चाहता था जिसने मेरी मदद की:

अपने आवेदन के घटकों (या वस्तुओं) के बारे में फेसबुक मित्रों के एक बड़े समूह के रूप में सोचें।

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

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

किसी चीज को लागू करने के लिए इवेंट श्रोताओं को बनाने या न बनाने का फैसला करते समय, इस सादृश्य के बारे में सोचें। क्या इस घटक को किसी को देखने के लिए अपने व्यवसाय को बाहर रखने की आवश्यकता है? या क्या उन्हें किसी को सीधे फोन करने की आवश्यकता है? चीजें बहुत आसानी से गड़बड़ हो सकती हैं इसलिए सावधान रहें।


0

यह निम्नलिखित सादृश्य आपको डॉक्टर के रिसेप्शन डेस्क पर प्रतीक्षा रेखा के समानांतर ड्राइंग द्वारा इवेंट संचालित I / O प्रोग्रामिंग को समझने में मदद कर सकता है।

I / O को अवरुद्ध करना पसंद है, यदि आप कतार में खड़े हैं, तो रिसेप्शनिस्ट आपके सामने एक व्यक्ति को फॉर्म भरने के लिए कहता है और वह तब तक इंतजार करता है जब तक वह खत्म नहीं हो जाता। आपको अपनी बारी का इंतजार करना होगा जब तक कि लड़का अपना फॉर्म पूरा नहीं कर लेता, यह ब्लॉक हो रहा है।

अगर सिंगल आदमी को भरने के लिए 3 मिनट लगते हैं, तो 10 वें आदमी को 30 मिनट तक इंतजार करना होगा। अब इस 10 वें लोगों के इंतजार के समय को कम करने के लिए, समाधान होगा, रिसेप्शनिस्ट की संख्या बढ़ाना, जो महंगा है। पारंपरिक वेब सर्वरों में ऐसा होता है। यदि आप एक उपयोगकर्ता जानकारी के लिए अनुरोध करते हैं, तो अन्य उपयोगकर्ताओं द्वारा बाद के अनुरोध को वर्तमान ऑपरेशन तक इंतजार करना चाहिए, डेटाबेस से प्राप्त करना, पूरा हो गया है। यह 10 वें अनुरोध के "प्रतिक्रिया के समय" को बढ़ाता है और यह nth उपयोगकर्ता के लिए तेजी से बढ़ता है। इस पारंपरिक वेब सर्वर से बचने के लिए हर एक अनुरोध के लिए थ्रेड (रिसेप्शनिस्ट की बढ़ती संख्या के बराबर), यानी, मूल रूप से यह प्रत्येक अनुरोध के लिए सर्वर की एक प्रति बनाता है, जो कि सीपीयू की खपत से महंगा होता है क्योंकि हर अनुरोध के लिए एक ऑपरेटिंग सिस्टम की आवश्यकता होती है धागा। एप्लिकेशन को स्केल करने के लिए,

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

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