प्रतिक्रियाशील प्रोग्रामिंग का परिचय

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

लक्ष्य प्रतिक्रियाशील प्रोग्रामिंग की मूल अवधारणाओं को पेश करना है और यह दिखाना है कि सब कुछ उतना जटिल और डरावना नहीं है जितना कि यह पहली नज़र में लग सकता है।

छवि
स्रोत

प्रतिक्रियाशील प्रोग्रामिंग क्या है?


इस प्रश्न का उत्तर देने के लिए, हम साइट पर जाते हैं । इसकी एक सुंदर तस्वीर है जो 4 मुख्य मानदंड दिखाती है जो प्रतिक्रियात्मक अनुप्रयोगों को पूरा करना चाहिए।

छवि

आवेदन तेजी से, दोष सहिष्णु और पैमाने पर होना चाहिए।
ऐसा लगता है कि "हम सभी अच्छे बनाम सभी बुरे हैं", है ना?

इन शब्दों से क्या अभिप्राय है:

  1. कोमलता

    एप्लिकेशन को उपयोगकर्ता को आधे सेकंड में परिणाम देना चाहिए। इसमें तेजी से विफल होने का सिद्धांत भी शामिल है - अर्थात, जब कुछ गलत होता है, तो त्रुटि संदेश वापस करना बेहतर होता है जैसे "क्षमा करें, एक समस्या थी। बाद में फिर से कोशिश करें कि मौसम समुद्र के द्वारा प्रतीक्षा करें। यदि ऑपरेशन लंबा है, तो हम उपयोगकर्ता को एक प्रगति बार दिखाते हैं। यदि यह बहुत लंबा है - “आपका अनुरोध 18 मार्च 2042 को अस्थायी रूप से पूरा हो जाएगा। हम आपको मेल में एक नोटिफिकेशन भेजेंगे। ”
  2. स्केलेबिलिटी लोड के तहत जवाबदेही प्रदान करने का एक तरीका है। अपेक्षाकृत सफल सेवा के जीवन चक्र की कल्पना करें:
    1. लॉन्च - अनुरोध प्रवाह छोटा है, सेवा एक कोर के साथ आभासी मशीन पर चलती है।
    2. अनुरोधों का प्रवाह बढ़ता है - गुठली को आभासी मशीन में जोड़ा जाता है और अनुरोधों को कई थ्रेड्स में संसाधित किया जाता है।
    3. और भी अधिक लोड - हम बैचिंग - डेटाबेस के अनुरोध और हार्ड ड्राइव को समूहीकृत करते हैं।
    4. और भी अधिक लोड - आपको अधिक सर्वर जुटाने और क्लस्टर में काम प्रदान करने की आवश्यकता है।
      आदर्श रूप से, सिस्टम को स्वयं लोड के आधार पर ऊपर या नीचे स्केल करना चाहिए।
  3. दोष सहिष्णुता

    हम स्वीकार करते हैं कि हम एक अपूर्ण दुनिया में रहते हैं और सब कुछ होता है। यदि हमारे सिस्टम में कुछ गलत हो जाता है, तो हमें त्रुटि से निपटने और पुनर्प्राप्ति के तरीके प्रदान करने होंगे
  4. और अंत में, हमें एक प्रणाली का उपयोग करके यह सब प्राप्त करने के लिए आमंत्रित किया जाता है जिसकी वास्तुकला संदेश-चालित संदेश पर आधारित है

जारी रखने से पहले, मैं इस बात पर ध्यान देना चाहता हूं कि ईवेंट-चालित सिस्टम संदेश-चालित सिस्टम से कैसे भिन्न होते हैं।

घटना-संचालित:

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

संदेश-चालित प्रणाली में घटना-संचालित के विपरीत:

  • प्रत्येक संदेश में केवल एक प्राप्तकर्ता होता है।
  • संदेश अपरिवर्तनीय हैं: आप प्राप्त संदेश में कुछ भी नहीं बदल सकते हैं ताकि प्रेषक को इसके बारे में पता हो और वह जानकारी पढ़ सके।
  • सिस्टम के तत्व संदेश प्राप्त करने के लिए प्रतिक्रिया देते हैं (या प्रतिक्रिया नहीं देते हैं) और सिस्टम के अन्य तत्वों को संदेश भेज सकते हैं।

यह सब हमें प्रदान करता है

अभिनेता मॉडल


विकास के मील के पत्थर:

  • अभिनेताओं का पहला उल्लेख 1973 के वैज्ञानिक शोधपत्र में है - कार्ल हेविट, पीटर बिशप और रिचर्ड स्टीगर, "कृत्रिम बुद्धिमत्ता के लिए एक सार्वभौमिक मॉड्यूलर ACTOR औपचारिकता"
  • 1986 - एर्लांग दिखाई दिया। एंडरसन को दूरसंचार उपकरणों के लिए एक भाषा की आवश्यकता थी जो दोष सहिष्णुता और त्रुटि मुक्त प्रचार प्रदान करेगा। इस लेख के संदर्भ में, इसकी मुख्य विशेषताएं हैं:

    • सब कुछ एक प्रक्रिया है
    • संदेश संचार का एकमात्र तरीका है (एर्लांग एक कार्यात्मक भाषा है, और इसमें संदेश अपरिवर्तनीय हैं)।
  • ...
  • 2004 - स्काला भाषा का पहला संस्करण। इसकी विशेषताएं:
    • जेवीएम द्वारा संचालित,
    • कार्यात्मक
    • मल्टी-थ्रेडिंग के लिए, एक अभिनेता मॉडल का चयन किया गया है।

  • 2009 - अभिनेताओं के कार्यान्वयन को एक अलग पुस्तकालय में आवंटित किया गया था - अक्का
  • 2014 - अक्का.नेट - इसे .Net पर पोर्ट किया गया था।

अभिनेता क्या कर सकते हैं?


अभिनेता एक ही वस्तु हैं, लेकिन:

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

आइए एक उदाहरण देखें।

छवि

अभिनेता ए अभिनेता बी को संदेश भेजना चाहता है। उसके पास सभी अभिनेता (कुछ पता) हैं। अभिनेता बी कहीं भी हो सकता है।
अभिनेता A सिस्टम (ActorSystem) के माध्यम से एक पत्र B भेजता है। यह सिस्टम अभिनेता बी के मेलबॉक्स में पत्र डालता है और अभिनेता बी। अभिनेता बी। मेलबॉक्स से पत्र लेता है और कुछ करता है।

किसी अन्य ऑब्जेक्ट पर कॉलिंग विधियों की तुलना में, यह अनावश्यक रूप से जटिल दिखता है, लेकिन अभिनेताओं का मॉडल वास्तविक दुनिया में पूरी तरह से फिट बैठता है, अगर आपको लगता है कि अभिनेता ऐसे लोग हैं जो कुछ उत्तेजनाओं के जवाब में कुछ करने के लिए प्रशिक्षित होते हैं।

पिता और पुत्र की कल्पना करें:



पिता अपने बेटे को एसएमएसू "कमरे में साफ" भेजता है और अपना काम खुद करता है। बेटा SMSku पढ़ता है और सफाई शुरू करता है। इस बीच, पिता पोकर खेल रहे हैं। बेटा सफाई करता है और एसएमएस "फिनिश" भेजता है। यह सरल लगता है, है ना?

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

अब आगे बढ़ते हैं

Akka.NET


नीचे लिखा गया सब कुछ जेवीएम के लिए मूल अक्का के लिए सही है, लेकिन मेरे लिए, सी # जावा की तुलना में करीब है, इसलिए मैं एक उदाहरण के रूप में अक्का.नेट का उपयोग करूंगा।

तो अक्का के फायदे क्या हैं?


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

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

हैंडलिंग में त्रुटि


अभिनेताओं के पास एक पदानुक्रम है - इसे एक पेड़ के रूप में दर्शाया जा सकता है। प्रत्येक अभिनेता के माता-पिता होते हैं और "बच्चे" हो सकते हैं।

छवि
Akka.NET प्रलेखन कॉपीराइट 2013-2018 Akka.NET परियोजना

प्रत्येक अभिनेता के लिए, आप एक पर्यवेक्षण रणनीति निर्धारित कर सकते हैं - "बच्चों" के लिए कुछ गलत होने पर क्या करना है। उदाहरण के लिए, "बीट" एक अभिनेता जो समस्याएँ रखता है, और फिर उसी प्रकार का एक नया अभिनेता बनाता है और उसे एक ही काम सौंपता है।

उदाहरण के लिए, मैंने Akka.net CRUD पर एक आवेदन किया, जिसमें अभिनेताओं पर "व्यावसायिक तर्क" की परत लागू की गई है। इस परियोजना का उद्देश्य यह पता लगाना था कि क्या अभिनेताओं को गैर-स्केलेबल सिस्टम में उपयोग किया जाना चाहिए - क्या वे जीवन को बेहतर बनाएंगे या अधिक दर्द जोड़ेंगे।

अक्का की अंतर्निहित त्रुटि हैंडलिंग कैसे मदद कर सकती है:

Gif


  1. सब कुछ ठीक है, आवेदन काम करता है,
  2. रिपॉजिटरी के लिए कुछ हुआ, और अब यह 5 में से केवल 1 बार परिणाम देता है,
  3. मैंने "प्रति सेकंड 10 बार प्रयास करने" के लिए पर्यवेक्षण रणनीति निर्धारित की,
  4. एप्लिकेशन फिर से काम कर रहा है (यद्यपि धीमे), और मेरे पास यह पता लगाने का समय है कि मामला क्या है।

यह कहने के लिए एक प्रलोभन है: "चलो, मैं खुद को संभालने में ऐसी त्रुटि लिखूंगा, कुछ अभिनेताओं को गलती क्यों करनी पड़ती है?" निष्पक्ष टिप्पणी, लेकिन केवल अगर विफलता के बिंदु कम हैं।

और कुछ कोड। इस तरह से आईओसी कंटेनर में अभिनेता प्रणाली का आरंभीकरण इस तरह दिखता है:

public Container() { system = ActorSystem.Create("MySystem"); var echo = system.ActorOf<EchoActor>("Echo"); //stop initialization if something is wrong with actor system var alive = echo.Ask<bool>(true, TimeSpan.FromMilliseconds(100)).Result; container = new WindsorContainer(); //search for dependencies //register controllers //register ActorSystem propsResolver = new WindsorDependencyResolver(container, (ActorSystem)system); system.AddDependencyResolver(propsResolver); actorSystemWrapper = new ActorSystemWrapper(system, propsResolver); container.Register(Component.For<IActorRefFactory>().Instance(actorSystemWrapper)); container.Register(Component.For<IDependencyResolver>().Instance(propsResolver)); } 

EchoActor सबसे सरल अभिनेता है जो प्रेषक को एक मूल्य देता है:

  public class EchoActor : ReceiveActor { public EchoActor() { Receive<bool>(flag => { Sender.Tell(flag); }); } } 

अभिनेताओं को "नियमित" कोड से जोड़ने के लिए, कमांड का उपयोग किया जाता है:

  public async Task<ActionResult> Index() { ViewBag.Type = typeof(Model); var res = await CrudActorRef.Ask<IEnumerable<Model>>(DataMessage.GetAll<Model>(), maxDelay); return View(res); } 

कुल मिलाकर


अभिनेताओं के साथ चुपके से, मैं कह सकता हूं:

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

      * शायद, एक निर्भरता को एक वस्तु में इंजेक्ट करने के बजाय, आपको इस निर्भरता को एक बाल अभिनेता के रूप में रखना चाहिए।
    • टाइपिंग की समस्याएं। ActorRef कुछ भी नहीं जानता कि वह किस प्रकार के अभिनेता के बारे में बताता है। अर्थात्, संकलन के समय यह ज्ञात नहीं है कि कोई अभिनेता इस प्रकार के संदेश को संसाधित कर सकता है या नहीं।

भाग 2: जेट स्ट्रीम


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


Rx धाराएँ सभी लोकप्रिय प्रोग्रामिंग भाषाओं के लिए उपलब्ध हैं।

CC BY-NC 4.0 के तहत लाइसेंस प्राप्त आंद्रे स्टाल्ट्ज द्वारा " रिएक्टिव प्रोग्रामिंग का परिचय जो आपको याद आ रहा है "

यह समझने के लिए कि जेट स्ट्रीम क्या है, मैं पुल और पुश संग्रह के साथ शुरू करूँगा।
एकल वापसी मूल्यएकाधिक वापसी मान
पुल
एक समय का
इंटरएक्टिव
टीIEnumerable <T>
धक्का
अतुल्यकालिक
रिएक्टिव
टास्क <टी>IObservable <T>

खींचे गए संग्रह वे हैं जिनका हम सभी प्रोग्रामिंग में उपयोग करते हैं। सबसे महत्वपूर्ण उदाहरण एक सरणी है।

 const arr = [1,2,3,4,5]; 

इसके पास पहले से ही डेटा है, वह खुद इस डेटा को नहीं बदलेगा, लेकिन वह इसे अनुरोध पर दे सकता है।

 arr.forEach(console.log); 

इसके अलावा, इससे पहले कि आप डेटा के साथ कुछ करें, आप किसी तरह इसे संसाधित कर सकते हैं।

 arr.map(i => i+1).map(I => “my number is ”+i).forEach(console.log); 

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

उदाहरण के लिए:

 source.map(i => i+1).map(I => “my number is ”+i).forEach(console.log); 

जब एक मान जैसे कि 1 स्रोत में दिखाई देता है, तो कंसोल.लॉग "मेरा नंबर 1 है" आउटपुट होगा।

यह कैसे काम करता है:

एक नई इकाई दिखाई देती है - विषय (या अवलोकनीय):

 const observable = Rx.Observable.create(function (observer) { observer.next(1); observer.next(2); observer.next(3); setTimeout(() => { observer.next(4); observer.complete(); }, 1000); }); 

यह एक धक्का संग्रह है जो अपने राज्य में परिवर्तनों के बारे में सूचनाएं भेजेगा।

इस स्थिति में, नंबर 1, 2 और 3 तुरंत इसमें दिखाई देंगे, एक दूसरे 4 में, और फिर संग्रह "समाप्त" होगा। यह एक विशेष प्रकार का आयोजन है।

दूसरी इकाई ऑब्जर्वर है। वह सब्जेक्ट इवेंट्स को सब्सक्राइब कर सकता है और प्राप्त डेटा के साथ कुछ कर सकता है। उदाहरण के लिए:

 observable.subscribe(x => console.log(x)); observable.subscribe({ next: x => console.log('got value ' + x), error: err => console.error('something wrong occurred: ' + err), complete: () => console.log('done'), }); observable .map(x => 'This is ' + x) .subscribe(x => console.log(x)); 

यह देखा जा सकता है कि एक विषय में कई ग्राहक हो सकते हैं।

यह आसान लग रहा है, लेकिन यह अभी तक स्पष्ट नहीं है कि यह क्यों आवश्यक है। मैं 2 और परिभाषाएँ दूंगा जिन्हें आपको प्रतिक्रियाशील प्रवाह के साथ काम करते समय जानना होगा, और फिर मैं अभ्यास में दिखाऊंगा कि वे कैसे काम करते हैं और किन स्थितियों में उनकी पूरी क्षमता का पता चलता है।

शीत वेधशालाएँ


  • घटनाओं के बारे में सूचित करें जब कोई उन्हें सदस्यता देता है।
  • सदस्यता के समय की परवाह किए बिना, पूरे डेटा स्ट्रीम को प्रत्येक ग्राहक को फिर से भेजा जाता है।
  • प्रत्येक ग्राहक के लिए डेटा कॉपी किया जाता है।

इसका क्या मतलब है: मान लीजिए कि कंपनी (विषय) ने उपहारों के वितरण की व्यवस्था करने का फैसला किया। प्रत्येक कर्मचारी (ऑब्जर्वर) काम करने के लिए आता है और उपहार की अपनी प्रति प्राप्त करता है। कोई भी वंचित नहीं रहे।

गर्म वेधशालाएँ


  • वे ग्राहकों की उपस्थिति की परवाह किए बिना घटना को सूचित करने का प्रयास करते हैं। यदि घटना के समय ग्राहक नहीं थे, तो डेटा खो जाता है।

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

जेट धाराओं का उपयोग किन स्थितियों में किया जाता है?


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

छवि
RxJs संदर्भ / अवलोकन योग्य , दस्तावेज़ीकरण CC BY 4.0 के तहत लाइसेंस प्राप्त है
(ऐसे कई उदाहरण और चित्र हैं जो बताते हैं कि प्रतिक्रियात्मक प्रवाह के साथ विभिन्न ऑपरेशन क्या करते हैं)

 source.bufferTime(2000).subsribe(doThings); 

और अंत में, उपयोग का एक उदाहरण।

आरएक्स धाराओं के साथ माउस इशारों को पहचानना


पुराने ओपेरा या इसके आध्यात्मिक उत्तराधिकारी - विवाल्डी में - माउस के इशारों का उपयोग करते हुए एक ब्राउज़र नियंत्रण था।

जिफ - विवाल्डी में माउस के हावभाव


यही है, आपको माउस आंदोलनों को ऊपर / नीचे, दाएं / बाएं, और उसके संयोजन को पहचानने की आवश्यकता है। यह आरएक्स धाराओं के बिना लिखा जा सकता है, लेकिन कोड जटिल और बनाए रखना मुश्किल होगा।

और यहाँ यह आरएक्स धाराओं के साथ कैसा दिखता है:


मैं अंत से शुरू करूँगा - मैंने यह निर्धारित किया है कि मैं मूल अनुक्रम में क्या डेटा और किस प्रारूप में खोज करूँगा:

 //gestures to look for const gestures = Rx.Observable.from([ { name: "Left", sequence: Rx.Observable.from([{ x: -1, y: 0 }]) }, { name: "Right", sequence: Rx.Observable.from([{ x: 1, y: 0 }]) }, { name: "Up", sequence: Rx.Observable.from([{ x: 0, y: -1 }]) }, { name: "Down", sequence: Rx.Observable.from([{ x: 0, y: 1 }]) }, { name: "Down+Up", sequence: Rx.Observable.from([{ x: 0, y: 1 }, { x: 0, y: -1 }]) }, { name: "Up+Right", sequence: Rx.Observable.from([{ x: 0, y: -1 }, { x: 1, y: 0 }]) } ]); 

ये यूनिट वैक्टर और उनके संयोजन हैं।

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

 const mouseMoves = Rx.Observable.fromEvent(canvas, 'mousemove'), mouseDowns = Rx.Observable.fromEvent(canvas, 'mousedown'), mouseUps = Rx.Observable.fromEvent(canvas, 'mouseup'); 

अगला, मैं माउस के निर्देशांक को 2 से समूहित करता हूं और माउस को ऑफसेट करते हुए, उनके अंतर को पाता हूं।

 const mouseDiffs = mouseMoves .map(getOffset) .pairwise() .map(pair => { return { x: pair[1].x-pair[0].x, y: pair[1].y-pair[0].y } }); 

और इन मूवमेंट्स को 'मूसेडाउन' और 'माउसअप' इवेंट का उपयोग करके समूह बनाएं।

 const mouseGestures = mouseDiffs .bufferToggle(mouseDowns, x => mouseUps) .map(concat); 

कॉनकैट फ़ंक्शन उन आंदोलनों को काट देता है जो बहुत कम हैं और समूह आंदोलनों को दिशा में मोटे तौर पर गठबंधन किया जाता है।

 function concat(values) {//summarize move in same direction return values.reduce((a, v) => { if (!a.length) { a.push(v); } else { const last = a[a.length - 1]; const lastAngle = Math.atan2(last.x, last.y); const angle = Math.atan2(vx, vy); const angleDiff = normalizeAngle(angle - lastAngle); const dist = Math.hypot(vx, vy); if (dist < 1) return a;//move is too short – ignore //moving in same direction => adding vectors if (Math.abs(angleDiff) <= maxAngleDiff) { last.x += vx; last.y += vy; } else { a.push(v); } } return a; }, []); } 

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

 const normalizedMouseGestures = mouseGestures.map(arr => arr.map(v => { const dist = Math.hypot(vx, vy);//length of vector vx = Math.abs(vx) > minMove && Math.abs(vx) * treshold > dist ? vx : 0; vy = Math.abs(vy) > minMove && Math.abs(vy) * treshold > dist ? vy : 0; return v; }) ).map(arr => arr .map(v => { return { x: Math.sign(vx), y: Math.sign(vy) }; }) .filter(v => Math.hypot(vx, vy) > 0) ); 

परिणाम:

 gestures.map(gesture => normalizedMouseGestures.mergeMap( moves => Rx.Observable.from(moves) .sequenceEqual(gesture.sequence, comparer) ).filter(x => x).mapTo(gesture.name) ).mergeAll().subscribe(gestureName => actions[gestureName]()); 

अनुक्रमिक का उपयोग करते हुए, आप प्राप्त आंदोलनों को मूल लोगों के साथ तुलना कर सकते हैं और, अगर कोई मैच होता है, तो एक निश्चित कार्रवाई करें।

Gif


आप यहाँ इशारों से खेल सकते हैं

कृपया ध्यान दें कि, जेस्चर पहचान के अलावा, एचटीएमएल कैनवास पर प्रारंभिक और सामान्य दोनों माउस आंदोलनों की एक ड्राइंग भी है। कोड पठनीयता इससे ग्रस्त नहीं है।

जिससे एक और लाभ इस प्रकार है - Rx धाराओं की सहायता से लिखी गई कार्यक्षमता को आसानी से पूरक और विस्तारित किया जा सकता है।

परिणाम


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

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


All Articles