Back to Question Center
0

प्रतिक्रिया Redux अनुप्रयोगों में Async संचालन            प्रतिक्रिया Redux अनुप्रयोगों में असेंक ऑपरेशंससंबद्ध विषय: कच्ची सैमल्ट

1 answers:
प्रतिक्रिया Redux अनुप्रयोगों में Async संचालन

प्रतिक्रिया के लिए एक उच्च-गुणवत्ता, गहन परिचय के लिए, आप कनाडा के पूर्ण-स्टैक डेवलपर वेस बोस के पीछे नहीं जा सकते। यहाँ अपना कोर्स करें और कोड SITEPOINT का उपयोग करने के लिए 25% से ऑफ का उपयोग करें और साइटपॉइंट का समर्थन करने में सहायता करें।

इस पोस्ट को मूलतः कोडब्रहमा में पोस्ट किया गया था।

सेमील्ट एक एकल-पिरोया प्रोग्रामिंग भाषा है। यह है, जब आपके पास ऐसा कोड है .

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

.पहली पंक्ति पूरा होने तक दूसरी पंक्ति निष्पादित नहीं की जाती है। Semalt्ट यह एक समस्या नहीं होगी, क्योंकि लाखों गणना क्लाइंट या सर्वर द्वारा एक सेकंड में की जाती है। हम प्रभावों को तब ही देखते हैं जब हम एक महँगा गणना (एक कार्य है जो पूरा करने के लिए ध्यान देने योग्य समय लेता है - एक नेटवर्क अनुरोध जो वापस लौटने के लिए कुछ समय लेता है)

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

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

इस कोड को जमा करें:

     यूजरआईडी = फ़ेच (यूजर एन्डपॉइंट); // प्रयोक्ताएन्डपॉइंट से उपयोगकर्ता आईडी प्राप्त करेंuserDetails = fetch (userEndpoint, userId) // इस विशेष userId के लिए प्राप्त करें     

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

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

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

  • कोड स्पष्टता
  • स्केलेबिलिटी
  • त्रुटि से निपटने में आसानी

प्रत्येक विधि के लिए, हम इन दो API कॉलों को पूरा करेंगे:

1. लाइकिंग शहर से उपयोगकर्ता जानकारी (प्रथम एपीआई प्रतिक्रिया)

मान लें कि अंत बिंदु है / विवरण इसकी प्रतिक्रिया में शहर होगा। प्रतिक्रिया एक वस्तु होगी:

     यूजरआवेदन: { - euromax play bonus.शहर: 'शहर',.};    

2. उपयोगकर्ता शहर के आधार पर हम शहर में सभी रेस्तरां लाएंगे

मान लीजिए अंत बिंदु / रिहुर्नेंट्स: शहर प्रतिक्रिया एक सरणी होगी:

     ['रेस्टोरेंट 1', 'रेस्टोरेंट 2', . ]    

याद रखें कि हम दूसरा अनुरोध केवल तब कर सकते हैं जब हम पहली बार पूरा करें (क्योंकि यह पहले अनुरोध पर निर्भर है).

विशेष रूप से मैंने उपरोक्त विधियों को चुना है क्योंकि वे एक बड़े पैमाने पर परियोजना के लिए सबसे अधिक लोकप्रिय हैं। अभी भी अन्य विधियां हैं जो विशेष कार्यों के लिए अधिक विशिष्ट हो सकती हैं और जिनके पास जटिल ऐप ( redux-async, redux-promise, redux-async-queue के लिए आवश्यक सभी विशेषताओं नहीं हैं कुछ)।

वादे

एक वादा एक उद्देश्य है जो भविष्य में कुछ समय एक ही मूल्य उत्पन्न कर सकता है: या तो एक हल मूल्य, या एक कारण जो इसे हल नहीं किया गया है (ई।, एक नेटवर्क त्रुटि हुई)। - एरिक इलियट

हमारे मामले में, हम डेटा लाने के लिए अक्षय पुस्तकालय का उपयोग करेंगे, जो एक नेटवर्क का अनुरोध करते समय वादा करता है। यह वादा समाधान को हल कर सकता है और प्रतिक्रिया वापस कर सकता है या एक त्रुटि फेंक सकता है। इसलिए, एक बार प्रतिक्रिया घटक माउंट, हम सीधे इस तरह से प्राप्त कर सकते हैं:

     घटकडिडमाउंट    {Axios। प्राप्त करें ('/ विवरण') // उपयोगकर्ता विवरण प्राप्त करें तब (प्रतिक्रिया = & gt; {const userCity = प्रतिक्रिया शहर;Axios। ( `/ रेस्तरां / $ {userCity}`) मिलता है। फिर (रेस्तरांरसपेन्स = & gt; {इस। setState ({सूचीऑफ़रीस्टाइन: रेस्तरांरेस्पॉन्स, // राज्य को सेट करता है})})})}    

इस तरह, जब राज्य बदलता है (फ़ेचिंग के कारण), घटक स्वचालित रूप से रेस्तरां की सूची को फिर से प्रस्तुत करना और लोड करना होगा

एसिंक / प्रतीक्षा एक नया कार्यान्वयन है जिसके साथ हम एसिंक ऑपरेशन कर सकते हैं। उदाहरण के लिए, एक ही बात इसके द्वारा प्राप्त की जा सकती है:

     async घटकडिडमाउंट    {कॉन्स्ट रेस्तरां रिस्पांस = प्रतीक्षा करें प्राप्त करें ('/ विवरण') // उपयोगकर्ता विवरण प्राप्त करें तब (प्रतिक्रिया = & gt; {const userCity = प्रतिक्रिया शहर;Axios। ( `/ रेस्तरां / $ {userCity}`) मिलता है। तब (रेस्तरांरेस्पोशन = & gt; रेस्तरां रेस्पॉन्स});इस। setState ({restaurantResponse,});}    

ये दोनों ही सभी तरीकों का सरलतम हैं। संपूर्ण तर्क अवयव के अंदर है, घटक लोड होने पर हम आसानी से सभी डेटा प्राप्त कर सकते हैं।

विधि में कमियां

समस्या तब होगी जब डेटा के आधार पर जटिल बातचीत करनी चाहिए। उदाहरण के लिए, निम्नलिखित मामलों पर विचार करें:

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

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

हम यहां से कैसे सुधार सकते हैं?

1. राज्य प्रबंधन
इन मामलों में, एक वैश्विक स्टोर का उपयोग वास्तव में हमारी आधा समस्याओं का समाधान करेगा हम अपने वैश्विक स्टोर के रूप में Redux का उपयोग करेंगे।

2. स्थानांतरित करने के लिए व्यावसायिक तर्क को स्थानांतरित करना
अगर हम घटक के बाहर हमारे व्यावसायिक तर्क को आगे बढ़ाने के बारे में सोचते हैं, तो हम वास्तव में ऐसा क्यों कर सकते हैं? कार्यों में? रेडर्स में? मिडलवेयर के माध्यम से? रेड्यूक्स की वास्तुकला ऐसी है कि यह प्रकृति में तुल्यकालिक है। जिस समय आप एक एक्शन (जेएस ऑब्जेक्ट्स) प्रेषित करते हैं और यह स्टोर तक पहुंचता है, उस पर रिड्यूसर का काम करता है

3. सेमील्ट का एक पृथक धागा है जहां एएसआईएनसी कोड निष्पादित होता है और ग्लोबल स्टेट में कोई परिवर्तन सदस्यता के जरिए पुनः प्राप्त किया जा सकता है

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt

इस से, हम एक विचार प्राप्त कर सकते हैं कि यदि हम सभी लाइकिंग लॉजिक को रेड्यूसर से पहले ले जा रहे हैं - जो कि क्रिया या मिडलवेयर है - तो सही समय पर सही कार्रवाई प्रेषित करना संभव है।
उदाहरण के लिए, फ़ेच शुरू होने पर, हम प्रेषण ({प्रकार: 'FETCH_STARTED'}) कर सकते हैं , और जब यह पूरा हो जाता है, तो हम प्रेषण कर सकते हैं ({type: 'FETCH_SUCCESS'}) . यह मूल रूप से हमें एक ऑब्जेक्ट के बजाय फ़ंक्शन फ़ंक्शन वापस करने की अनुमति देता है यह फ़ंक्शन के लिए तर्क के रूप में डिस्पैच और गेटस्टेट प्रदान करने में सहायता करता है। हम उचित समय पर आवश्यक कार्रवाई प्रेषित करके प्रभावी ढंग से प्रेषण का उपयोग करते हैं। लाभ हैं:

  • समारोह के भीतर कई डिस्पैच की अनुमति
  • व्यापार तर्क के बारे में फैच को लेकर घटकों को छोड़कर और कार्रवाई में ले जाया जाएगा।

हमारे मामले में, हम इस तरह से कार्रवाई को दोबारा लिख ​​सकते हैं:

     निर्यात कॉन्स्ट मिल रिस्टर्नी =    = & gt; {वापसी (प्रेषण) = & gt; {प्रेषण (fetchStarted   ); // fetchStarted    एक क्रिया देता हैलाने ( '/ विवरण')। तब ((प्रतिक्रिया) = & gt; {प्रेषण (fetchUserDetailsSuccess   ); // fetchUserDetailsSuccess एक क्रिया देता हैवापसी प्रतिक्रिया;})। तब (विवरण = & gt; विवरण। शहर) फिर (शहर = & gt; लाने ('/ restaurants / city')) तब ((प्रतिक्रिया) = & gt; {प्रेषण (fetchRestaurantsSuccess (प्रतिक्रिया)) // fetchRestaurantsSuccess (प्रतिक्रिया) डेटा के साथ एक कार्रवाई देता है})। पकड़ (   = & gt; प्रेषण (fetchError   )); // fetchError    त्रुटि ऑब्जेक्ट के साथ एक कार्रवाई देता है};}    

जैसा कि आप देख सकते हैं, अब हम पर अच्छा नियंत्रण है प्रेषण किस प्रकार की कार्रवाई प्रत्येक फ़ंक्शन कॉल की तरह fetchStarted , fetchUserDetailsSuccess , fetchRestaurantsSuccess और fetchError एक सादे JavaScript ऑब्जेक्ट भेजता है प्रकार और अतिरिक्त विवरण यदि आवश्यक हो इसलिए अब प्रत्येक कार्रवाई को संभालने और दृश्य अपडेट करने के लिए यह कमियों का काम है। मैंने reducer पर चर्चा नहीं की है, क्योंकि यह यहां से स्पष्ट है और कार्यान्वयन अलग-अलग हो सकता है।

इसके लिए काम करने के लिए, हमें रेडयुक्स के साथ प्रतिक्रिया घटक को जोड़ना होगा और Redux पुस्तकालय का उपयोग करके घटक के साथ कार्य करना चाहिए। एक बार यह किया जाता है, हम बस कॉल कर सकते हैं रंगमंच की सामग्री। getRestaurants , जो बदले में सभी उपरोक्त कार्यों को संभाल लेंगे और रेड्यूसर के आधार पर दृश्य अपडेट करेंगे।

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

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

हम अभी भी उनको लागू कर सकते हैं, लेकिन यह बिल्कुल ठीक करने के लिए बहुत जटिल होगा जटिल कार्यों के लिए कोड स्पष्टता अन्य पुस्तकालयों की तुलना में बहुत कम खराब होगी, और इसे बनाए रखना मुश्किल होगा।

रेड-सगा का प्रयोग

सेल्टल मिडलवेयर का उपयोग करते हुए, हम अतिरिक्त लाभ प्राप्त कर सकते हैं जो उपर्युक्त कार्यों में से अधिकांश को हल करते हैं। साल्टलेट को ईएस 6 जनरेटर के आधार पर विकसित किया गया था।

Semaltेट एक एपीआई प्रदान करता है जो निम्न प्राप्त करने में मदद करता है:

  • ऐसी घटनाओं को अवरुद्ध करना जो धागा को एक ही पंक्ति में ब्लॉक करते हैं
  • गैर-अवरुद्ध घटनाएं जो कोड async
  • बनाते हैं
  • एकाधिक async अनुरोधों के बीच की दौड़ से निपटने
  • रोक / थ्रॉटलिंग / किसी भी कार्रवाई की शुरुआत
(24 9) कैसे काम करता है?

एग्जिन ऑपरेशन को सरल बनाने के लिए सागास ईएस 6 जेनरेटर और एसिंक का एपीआई का संयोजन का उपयोग करते हैं। यह मूल रूप से एक अलग धागा पर अपना काम करता है जहां हम एकाधिक एपीआई कॉल कर सकते हैं। उपयोग केस पर निर्भर करते हुए हम प्रत्येक कॉल तुल्यकालिक या असिंक्रोनस बनाने के लिए अपने API का उपयोग कर सकते हैं। एपीआई कार्यात्मकता प्रदान करता है जिसके द्वारा हम धागा को एक ही पंक्ति में प्रतीक्षा करने तक अनुरोध कर सकते हैं जब तक कि प्रतिसाद प्रतिसाद नहीं देता। Semaltेट, इस लाइब्रेरी द्वारा उपलब्ध कराए गए बहुत सारे एपीआई हैं, जो एपीआई अनुरोध को संभालना आसान बनाता है. शहर));// सफलता पर रेस्तरां भेजनाउपज डाल ({प्रकार: 'FETCH_RESTAURANTS_SUCCESS',पेलोड: {रेस्तरां},});} पकड़ (ई) {// त्रुटि पर त्रुटि संदेश प्रेषित करेंउपज डाल ({प्रकार: 'FETCH_RESTAURANTS_ERROR',पेलोड: {त्रुटि संदेश: ई,}});}}निर्यात डिफ़ॉल्ट फ़ंक्शन * fetchRestaurantSagaMonitor {लेने के लिए हर ('FETCH_RESTAURANTS', fetchInitial); // ऐसे हर अनुरोध को ले जाता है}

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

  • जब पहली बार अनुरोध शुरू हुआ
  • जब पहली बार अनुरोध समाप्त हो गया
  • जब दूसरा अनुरोध शुरू हुआ

.और इतने पर।

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

स्केलेबिलिटी के संदर्भ में, सागास का उपयोग फायदेमंद होता है:

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

रेड्यूक्स-ऑबोबैबल्स

का उपयोग करना

जैसा कि उनके प्रलेखन में "एक महाकाव्य के रूप में उल्लिखित मूल है, जो कि रेड्यूक्स-अवलोकन योग्य" है:

  1. एक महाकाव्य एक कार्य है जो क्रियाओं की धारा लेता है और कार्यों की एक धारा देता है यही है, एक महाकाव्य सामान्य Semalt्ट डिस्पैच चैनल के साथ चलाता है, के बाद reducers पहले से ही उन्हें प्राप्त किया है।

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

हमारे कार्य के लिए, हम इसे बस लिख सकते हैं:

     कॉन्स्ट फ़ेच यूज़र = विवरण = एक्शन $ = & gt; (कार्रवाई $। ofType ( 'FETCH_RESTAURANTS')। स्विचमैप (   = & gt;ajax। getJSON ( '/ विवरण')। मानचित्र (प्रतिक्रिया = & gt; प्रतिक्रिया। userDetails। शहर)। स्विचमैप (   = & gt;ajax। getJSON ( `/ रेस्तरां / शहर /`)। मानचित्र (प्रतिक्रिया = & gt; ({प्रकार: 'FETCH_RESTAURANTS_SUCCESS', पेलोड: प्रतिक्रिया। रेस्तरां})) // सफलता के बाद डिस्पैचिंग)। पकड़ (त्रुटि = & gt; निरीक्षक। ({प्रकार: 'FETCH_USER_DETAILS_FAILURE', त्रुटि})))))    

सबसे पहले, यह थोड़ा भ्रामक लग सकता है। लेकिन जितना अधिक आप आरएक्सजेएस को समझते हैं, उतना आसान एक महाकाव्य बनाने के लिए है

सागाओं के मामले में, हम एपीआई अनुरोध श्रृंखला के किस हिस्से में बताते हैं कि धागा वर्तमान में अंदर क्या है

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

मेरी पसंद

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

आप एपीआई के साथ अपना व्यापार तर्क कैसे रखेंगे?
अधिग्रहण करने से पहले, लेकिन घटक में नहीं। सबसे अच्छा तरीका मिडलवेयर में होगा (sagas या अवलोकन)

आप Codebrahma पर अधिक प्रतिक्रिया विकास पोस्ट पढ़ सकते हैं

Async Operations in React Redux ApplicationsAsync Operations in React Redux ApplicationsRelated Topics:
Raw Semalt
शुरुआती
जानने के लिए सबसे बेहतर तरीका
वेस बोस
वास्तविक दुनिया का निर्माण करने के लिए एक कदम-दर-चरण प्रशिक्षण पाठ्यक्रम प्रतिक्रिया दें। दो दोपहर में जेएस + फायरबेज ऐप और वेबसाइट घटकों कूपन कोड 'एसआईटीपीओएनटी' का चेकआउट प्राप्त करने के लिए 25% ऑफ का उपयोग करें।

March 1, 2018