प्रतिक्रियाशील प्रोग्रामिंग का सबसे छोटा परिचय

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


निम्नलिखित कार्य करें:
REST API और समापन बिंदु /people साथ एक निश्चित सेवा है। इस समापन बिंदु के लिए एक POST अनुरोध एक नई इकाई बनाता है। एक फ़ंक्शन लिखें जो प्रपत्र { name: 'Max' } ऑब्जेक्ट { name: 'Max' } की वस्तुओं की एक सरणी लेता है और एपीआई (अंग्रेजी में, इसे बैच ऑपरेशन कहा जाता है) का उपयोग करके संस्थाओं का एक सेट बनाएं।


आइए इस समस्या को एक अनिवार्य शैली में हल करें:


 const request = require('superagent') function batchCreate(bodies) { const calls = [] for (let body of bodies) { calls.push( request .post('/people') .send(body) .then(r => r.status) ) } return Promise.all(calls) } 

तुलना के लिए, आइए एक कार्यात्मक शैली में कोड के इस टुकड़े को फिर से लिखें। सादगी के लिए, हमारा मतलब कार्यात्मक शैली से है:


  1. अनिवार्य छोरों के बजाय कार्यात्मक प्राइमेटिव ( .map , .filter , .reduce ) का उपयोग (के लिए , जबकि )
  2. कोड "शुद्ध" कार्यों में आयोजित किया जाता है - वे केवल अपने तर्कों पर निर्भर करते हैं और सिस्टम की स्थिति पर निर्भर नहीं करते हैं

कार्यात्मक शैली कोड:


 const request = require('superagent') function batchCreate(bodies) { const calls = bodies.map(body => request .post('/people') .send(body) .then(r => r.status) ) return Promise.all(calls) } 

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


इस बिंदु पर, यह संभवतः स्वयं को रोकने और समस्या को हल करने के लायक है,% उपयोगकर्ता नाम%


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


प्रतिक्रियाशील धाराएँ क्या हैं? यदि बहुत संक्षेप में, तो यह एक दृष्टिकोण है जो आपको समय के साथ वितरित की गई चीज़ों के लिए कार्यात्मक प्रिमिटिव (.map, .filter, .reduce) लगाने की अनुमति देता है।


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


  • प्रवाह अनंत या मनमाने ढंग से समय के साथ वितरित किया जा सकता है
  • भेजने वाला पक्ष केवल तभी आदेश प्रेषित करता है जब प्राप्तकर्ता पक्ष इसे संसाधित करने के लिए तैयार होता है (बैकप्रेशर)

इस लेख का उद्देश्य आसान तरीके खोजना है, इसलिए, हम हाईलैंड लाइब्रेरी को ले जाएंगे, जो आरएक्स जैसी ही समस्या को हल करने की कोशिश करती है, लेकिन सीखना बहुत आसान है। अंदर का विचार सरल है: चलो एक आधार के रूप में Node.js स्ट्रीम लेते हैं और एक स्ट्रीम से दूसरे में "ट्रांसफर" डेटा।


आइए शुरू करें: चलो एक सरल के साथ शुरू करते हैं - हम नई कार्यक्षमता को जोड़ने के बिना हमारे कोड को "प्रतिक्रियाशील" बनाएंगे


 const request = require('superagent') const H = require('highland') function batchCreate(bodies) { return H(bodies) .flatMap(body => H(request .post('localhost:3000/people') .send(body) .then(r => r.status) ) ) .collect() .toPromise(Promise) } 

आपको किन बातों पर ध्यान देना चाहिए:


  • एच (निकायों) - हम एक सरणी से एक स्ट्रीम बनाते हैं
  • .flatMap और कॉलबैक जिसे वह स्वीकार करता है। विचार काफी सरल है - हम एक मूल्य (या एक त्रुटि) के साथ एक धारा प्राप्त करने के लिए एक धारा के निर्माणकर्ता में वादा लपेटते हैं। यह समझना महत्वपूर्ण है कि यह मूल्य है, वादा नहीं।
    नतीजतन, यह हमें प्रवाह की एक धारा प्रदान करता है - फ्लैट मैप का उपयोग करके हम इसे मूल्यों की एक धारा में सुचारू करते हैं जिसे हम संचालित कर सकते हैं (जिसने सन्यासी कहा था?)
  • .collect - हमें एक "पॉइंट" में सभी मानों को एक सरणी में इकट्ठा करने की आवश्यकता है
  • .toPromise - हमसे वह वादा वापस आएगा, जो उस समय पूरा होगा जब हमारे पास स्ट्रीम से वैल्यू होगी

अब हम अपनी आवश्यकता को लागू करने का प्रयास करते हैं:


 const request = require('superagent') const H = require('highland') function batchCreate(bodies) { return H(bodies) .flatMap(body => H(request .post('localhost:3000/people') .send(body) .then(r => r.status) ) ) .ratelimit(5, 1000) .collect() .toPromise(Promise) } 

बैकस्पेस की अवधारणा के लिए धन्यवाद, यह इस प्रतिमान में सिर्फ एक पंक्ति है ।ratelimit। Rx में, यह लगभग उतनी ही जगह लेता है


खैर यह सब, आपकी राय दिलचस्प है:


  • क्या मैंने लेख की शुरुआत में घोषित परिणाम को प्राप्त करने का प्रबंधन किया था?
  • क्या एक अनिवार्य दृष्टिकोण का उपयोग करके समान परिणाम प्राप्त करना संभव है?
  • क्या आप रिएक्टिव प्रोग्रामिंग में रुचि रखते हैं?

पुनश्च: यहां आप रिएक्टिव प्रोग्रामिंग के बारे में मेरा एक और लेख पा सकते हैं

Source: https://habr.com/ru/post/hi427467/


All Articles