"कॉलबैक नरक" क्या है और आरएक्स इसे कैसे और क्यों हल करता है?


113

क्या कोई सरल उदाहरण के साथ एक स्पष्ट परिभाषा दे सकता है जो बताता है कि जावास्क्रिप्ट और नोड .js को नहीं जानने वाले के लिए "कॉलबैक नरक" क्या है?

जब (किस तरह की सेटिंग्स में) "कॉलबैक नरक समस्या" होती है?

क्यों होता है?

क्या "कॉलबैक नरक" हमेशा अतुल्यकालिक गणनाओं से संबंधित है?

या "कॉलबैक नरक" एक भी थ्रेडेड एप्लिकेशन में भी हो सकता है?

मैंने कौरसेरा में रिएक्टिव कोर्स लिया और एरिक मीजर ने अपने एक व्याख्यान में कहा कि आरएक्स "कॉलबैक नरक" की समस्या को हल करता है। मैंने पूछा कि कौरसेरा मंच पर "कॉलबैक नरक" क्या है लेकिन मुझे कोई स्पष्ट जवाब नहीं मिला।

एक सरल उदाहरण पर "कॉलबैक नरक" की व्याख्या करने के बाद, क्या आप यह भी दिखा सकते हैं कि आरएक्स उस सरल उदाहरण पर "कॉलबैक नरक समस्या" को कैसे हल करता है?

जवाबों:


136

1) जो व्यक्ति जावास्क्रिप्ट और नोड्स नहीं जानता है, उसके लिए "कॉलबैक नरक" क्या है?

इस अन्य प्रश्न में जावास्क्रिप्ट कॉलबैक नरक के कुछ उदाहरण हैं: Node.ss में अतुल्यकालिक कार्यों के लंबे घोंसले से कैसे बचें

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

उदाहरण के लिए, मान लीजिए कि मैं इस तरह दिखने वाला कोड चलाना चाहता हूं:

x = getData();
y = getMoreData(x);
z = getMoreData(y);
...

क्या होगा अगर अब मैं गेटडाटा कार्यों को अतुल्यकालिक बनाना चाहता हूं, जिसका अर्थ है कि मुझे कुछ अन्य कोड चलाने का मौका मिलता है जबकि मैं उनके मूल्यों को वापस करने के लिए इंतजार कर रहा हूं? जावास्क्रिप्ट में, एकमात्र तरीका वह सब कुछ फिर से लिखना होगा जो निरंतर गुजर शैली का उपयोग करके एक एसिंक्स कम्प्यूटेशन को छूता है :

getData(function(x){
    getMoreData(x, function(y){
        getMoreData(y, function(z){ 
            ...
        });
    });
});

मुझे नहीं लगता कि मुझे किसी को यह समझाने की जरूरत है कि यह संस्करण पिछले वाले की तुलना में बदसूरत है। :-)

2) कब (किस तरह की सेटिंग्स में) "कॉलबैक नरक समस्या" होती है?

जब आप अपने कोड में बहुत सारे कॉलबैक कार्य करते हैं! उनके साथ काम करना कठिन हो जाता है, आपके पास उनके कोड में अधिक है और यह विशेष रूप से खराब हो जाता है जब आपको लूप्स, ट्राइ-कैच ब्लॉक और इस तरह की चीजों को करने की आवश्यकता होती है।

उदाहरण के लिए, जहां तक ​​मुझे पता है, जावास्क्रिप्ट में अतुल्यकालिक कार्यों की एक श्रृंखला को निष्पादित करने का एकमात्र तरीका है जहां एक पिछले रिटर्न के बाद चलाया जाता है, एक पुनरावर्ती फ़ंक्शन का उपयोग कर रहा है। आप लूप के लिए उपयोग नहीं कर सकते।

// we would like to write the following
for(var i=0; i<10; i++){
    doSomething(i);
}
blah();

इसके बजाय, हमें लेखन को समाप्त करने की आवश्यकता हो सकती है:

function loop(i, onDone){
    if(i >= 10){
        onDone()
    }else{
        doSomething(i, function(){
            loop(i+1, onDone);
        });
     }
}
loop(0, function(){
    blah();
});

//ugh!

StackOverflow पर हमें यहाँ कितने प्रश्न मिलते हैं यह पूछने के लिए कि इस तरह का काम कैसे किया जाता है, यह कितना भ्रामक है। :)

३) ऐसा क्यों होता है?

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

4) या "कॉलबैक नरक" भी एक ही थ्रेडेड एप्लिकेशन में हो सकता है?

अतुल्यकालिक प्रोग्रामिंग को संगति के साथ करना पड़ता है जबकि एकल-सूत्र को समानता के साथ करना पड़ता है। दो अवधारणाएं वास्तव में एक ही चीज नहीं हैं।

आप अभी भी एकल थ्रेडेड संदर्भ में समवर्ती कोड रख सकते हैं। वास्तव में, कॉलबैक नरक की रानी, ​​जावास्क्रिप्ट, सिंगल थ्रेडेड है।

समवर्ती और समानता के बीच अंतर क्या है?

5) क्या आप यह भी दिखा सकते हैं कि RX उस सरल उदाहरण पर "कॉलबैक नरक समस्या" को कैसे हल करता है।

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

पायथन में हम उस पिछले लूप उदाहरण को कुछ की तर्ज पर लागू कर सकते हैं:

def myLoop():
    for i in range(10):
        doSomething(i)
        yield

myGen = myLoop()

यह पूर्ण कोड नहीं है, लेकिन विचार यह है कि "उपज" हमारे लूप के लिए रोकती है जब तक कोई myGen.next () को कॉल नहीं करता है। महत्वपूर्ण बात यह है कि हम लूप के लिए कोड का उपयोग तब भी कर सकते हैं, बिना तर्क को "अंदर बाहर" करने की आवश्यकता के बिना, जैसे हमें उस पुनरावर्ती loopकार्य में करना था ।


तो कॉलबैक नरक केवल एक async सेटिंग में हो सकता है? अगर मेरा कोड पूरी तरह से साइक्रोनस है (यानी कोई कंसीलर नहीं) तो "कॉलबैक नरक" नहीं हो सकता है अगर मैं आपके उत्तर को सही ढंग से समझूं, तो क्या यह सही है?
19

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

btw, मैं प्रतिक्रियाशील एक्सटेंशन के लिए googled और मुझे यह धारणा मिल रही है कि वे एक प्रोमिस लाइब्रेरी के समान हैं और न कि भाषा विस्तार के लिए एसिंक्स सिंटैक्स की शुरुआत। वादे कॉलबैक घोंसले से निपटने और अपवाद से निपटने में मदद करते हैं लेकिन वे सिंटैक्स एक्सटेंशन के रूप में साफ-सुथरे होते हैं। लूप के लिए अभी भी कोड के लिए कष्टप्रद है और आपको अभी भी कोड को तुल्यकालिक शैली से वादा शैली में अनुवाद करना होगा।
hugomg

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

एक और अधिक संबंधित टिप्पणी: आरएक्स मूल रूप से निरंतरता वाला मोनाड है, जो सीपीएस से संबंधित है अगर मैं गलत नहीं हूं, तो यह भी बता सकता है कि कॉलबैक / नरक समस्या के लिए आरएक्स कैसे / क्यों अच्छा है।
jhegedus

30

बस इस सवाल का जवाब दें: क्या आप यह भी दिखा सकते हैं कि RX उस सरल उदाहरण पर "कॉलबैक नरक समस्या" को कैसे हल करता है?

जादू है flatMap। हम @ hugomg के उदाहरण के लिए Rx में निम्न कोड लिख सकते हैं:

def getData() = Observable[X]
getData().flatMap(x -> Observable[Y])
         .flatMap(y -> Observable[Z])
         .map(z -> ...)...

यह ऐसा है जैसे आप कुछ सिंक्रोनस एफपी कोड लिख रहे हैं, लेकिन वास्तव में आप उन्हें एसिंक्रोनस बना सकते हैं Scheduler


26

कैसे Rx कॉलबैक नरक हल करता है के सवाल को हल करने के लिए :

पहले चलो फिर से कॉलबैक नरक का वर्णन करते हैं।

एक मामले की कल्पना करें कि हमें तीन संसाधन - व्यक्ति, ग्रह और आकाशगंगा प्राप्त करने के लिए http करना चाहिए। हमारा उद्देश्य उस आकाशगंगा को खोजना है, जिसमें व्यक्ति रहता है। पहले हमें उस व्यक्ति को, फिर ग्रह, फिर आकाशगंगा को प्राप्त करना चाहिए। यह तीन अतुल्यकालिक संचालन के लिए तीन कॉलबैक हैं।

getPerson(person => { 
   getPlanet(person, (planet) => {
       getGalaxy(planet, (galaxy) => {
           console.log(galaxy);
       });
   });
});

प्रत्येक कॉलबैक नेस्टेड है। प्रत्येक आंतरिक कॉलबैक उसके माता-पिता पर निर्भर है। यह कॉलबैक नरक की "कयामत के पिरामिड" शैली की ओर जाता है । कोड> साइन की तरह दिखता है।

RxJs में इसे हल करने के लिए आप ऐसा कुछ कर सकते हैं:

getPerson()
  .map(person => getPlanet(person))
  .map(planet => getGalaxy(planet))
  .mergeAll()
  .subscribe(galaxy => console.log(galaxy));

साथ mergeMapउर्फ flatMapऑपरेटर आप इसे और अधिक संक्षिप्त कर सकता है:

getPerson()
  .mergeMap(person => getPlanet(person))
  .mergeMap(planet => getGalaxy(planet))
  .subscribe(galaxy => console.log(galaxy));

जैसा कि आप देख सकते हैं, कोड चपटा है और विधि कॉल की एक श्रृंखला है। हमारे पास "कयामत का पिरामिड" नहीं है।

इसलिए, कॉलबैक नरक से बचा जाता है।

यदि आप सोच रहे थे, तो कॉलबैक नरक से बचने के लिए वादे एक और तरीका है, लेकिन वादे उत्सुक हैं , वे पर्यवेक्षकों की तरह आलसी नहीं हैं और (आमतौर पर बोलते हुए) आप उन्हें आसानी से रद्द नहीं कर सकते।


मैं जेएस डेवलपर नहीं हूं, लेकिन यह आसान विवरण है
उमर बेशरी

15

कॉलबैक नरक कोई भी कोड है जहां async कोड में फ़ंक्शन कॉलबैक का उपयोग अस्पष्ट या पालन करना मुश्किल हो जाता है। आम तौर पर, जब एक स्तर से अधिक अप्रत्यक्ष होता है, तो कॉलबैक का उपयोग करने वाला कोड पालन करने के लिए कठिन, रिफ्लेक्टर के लिए कठिन और परीक्षण के लिए कठिन हो सकता है। एक कोड गंध फ़ंक्शन लिटरल की कई परतों को पारित करने के कारण इंडेंटेशन के कई स्तर हैं।

ऐसा अक्सर तब होता है जब व्यवहार पर निर्भरता होती है, यानी जब A को B से पहले C से पहले होना चाहिए। तब आपको इस तरह का कोड मिलता है:

a({
    parameter : someParameter,
    callback : function() {
        b({
             parameter : someOtherParameter,
             callback : function({
                 c(yetAnotherParameter)
        })
    }
});

यदि आपके पास इस तरह के व्यवहार में बहुत अधिक निर्भरता है, तो यह तेजी से परेशान कर सकता है। खासकर अगर यह शाखाओं ...

a({
    parameter : someParameter,
    callback : function(status) {
        if (status == states.SUCCESS) {
          b(function(status) {
              if (status == states.SUCCESS) {
                 c(function(status){
                     if (status == states.SUCCESS) {
                         // Not an exaggeration. I have seen
                         // code that looks like this regularly.
                     }
                 });
              }
          });
        } elseif (status == states.PENDING {
          ...
        }
    }
});

यह नहीं चलेगा। हम इन सभी कॉलबैक को पास किए बिना एक निर्धारित क्रम में एसिंक्रोनस कोड निष्पादित कैसे कर सकते हैं?

RX 'रिएक्टिव एक्सटेंशन' के लिए कम है। मैंने इसका उपयोग नहीं किया है, लेकिन Googling ने सुझाव दिया है कि यह एक घटना-आधारित रूपरेखा है, जो समझ में आता है। भंगुर युग्मन बनाने के बिना कोड निष्पादित करने के लिए ईवेंट एक सामान्य पैटर्न हैं । आप C को 'bFinished' ईवेंट को सुन सकते हैं जो केवल B के बाद होता है जिसे 'aFinished' सुनने के लिए कहा जाता है। फिर आप आसानी से अतिरिक्त कदम जोड़ सकते हैं या इस तरह के व्यवहार का विस्तार कर सकते हैं , और आसानी से परीक्षण कर सकते हैं कि आपका कोड आपके परीक्षण मामले में केवल घटनाओं को प्रसारित करके क्रम में निष्पादित होता है।


1

कॉल बैक नरक का मतलब है कि आप एक कॉलबैक के अंदर कॉलबैक के अंदर हैं और यह एनएचटी कॉल तक जाता है जब तक कि आपकी ज़रूरत पूरी न हो जाए।

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

<body>
    <script>
        function getRecipe(){
            setTimeout(()=>{
                const recipeId = [83938, 73838, 7638];
                console.log(recipeId);
            }, 1500);
        }
        getRecipe();
    </script>
</body>

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

<body>
    <script>
        function getRecipe(){
            setTimeout(()=>{
                const recipeId = [83938, 73838, 7638];
                console.log(recipeId);
                setTimeout(id=>{
                    const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
                    console.log(`${id}: ${recipe.title}`);
                }, 1500, recipeId[2])
            }, 1500);
        }
        getRecipe();
    </script>
</body>

किसी विशेष रेसिपी डेटा को डाउनलोड करने के लिए हमने अपनी पहली कॉलबैक और उत्तीर्ण रेसिपी आईडी के अंदर कोड लिखा।

अब हम कहते हैं कि हमें उसी प्रकाशक के सभी व्यंजनों को डाउनलोड करने की आवश्यकता है जो आईडी 7638 है।

<body>
    <script>
        function getRecipe(){
            setTimeout(()=>{
                const recipeId = [83938, 73838, 7638];
                console.log(recipeId);
                setTimeout(id=>{
                    const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
                    console.log(`${id}: ${recipe.title}`);
                    setTimeout(publisher=>{
                        const recipe2 = {title:'Fresh Apple Pie', publisher:'Suru'};
                        console.log(recipe2);
                    }, 1500, recipe.publisher);
                }, 1500, recipeId[2])
            }, 1500);
        }
        getRecipe();
    </script>
</body>

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

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

चलो एक वादे का उपयोग करके पिछली कॉलबैक नरक समस्या को हल करें।

<body>
    <script>

        const getIds = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                const downloadSuccessfull = true;
                const recipeId = [83938, 73838, 7638];
                if(downloadSuccessfull){
                    resolve(recipeId);
                }else{
                    reject('download failed 404');
                }
            }, 1500);
        });

        getIds.then(IDs=>{
            console.log(IDs);
        }).catch(error=>{
            console.log(error);
        });
    </script>
</body>

अब विशेष नुस्खा डाउनलोड करें:

<body>
    <script>
        const getIds = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                const downloadSuccessfull = true;
                const recipeId = [83938, 73838, 7638];
                if(downloadSuccessfull){
                    resolve(recipeId);
                }else{
                    reject('download failed 404');
                }
            }, 1500);
        });

        const getRecipe = recID => {
            return new Promise((resolve, reject)=>{
                setTimeout(id => {
                    const downloadSuccessfull = true;
                    if (downloadSuccessfull){
                        const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
                        resolve(`${id}: ${recipe.title}`);
                    }else{
                        reject(`${id}: recipe download failed 404`);
                    }

                }, 1500, recID)
            })
        }
        getIds.then(IDs=>{
            console.log(IDs);
            return getRecipe(IDs[2]);
        }).
        then(recipe =>{
            console.log(recipe);
        })
        .catch(error=>{
            console.log(error);
        });
    </script>
</body>

अब हम getRecipe की तरह एक और मेथड कॉल allRecipeOfAPublisher लिख सकते हैं जो एक वादा भी लौटाएगा, और हम allRecipeOfAPublisher के लिए संकल्प वादे को प्राप्त करने के लिए एक और () लिख सकते हैं, मुझे उम्मीद है कि इस बिंदु पर आप इसे खुद से कर सकते हैं।

तो हमने सीखा कि वादों का निर्माण और उपभोग कैसे किया जाता है, अब आइए हम एस 8 / एसिट का उपयोग करके एक वादे को आसान बनाते हैं जो एस 8 में पेश किया गया है।

<body>
    <script>

        const getIds = new Promise((resolve, reject)=>{
            setTimeout(()=>{
                const downloadSuccessfull = true;
                const recipeId = [83938, 73838, 7638];
                if(downloadSuccessfull){
                    resolve(recipeId);
                }else{
                    reject('download failed 404');
                }
            }, 1500);
        });

        const getRecipe = recID => {
            return new Promise((resolve, reject)=>{
                setTimeout(id => {
                    const downloadSuccessfull = true;
                    if (downloadSuccessfull){
                        const recipe = {title:'Fresh Apple Juice', publisher:'Suru'};
                        resolve(`${id}: ${recipe.title}`);
                    }else{
                        reject(`${id}: recipe download failed 404`);
                    }

                }, 1500, recID)
            })
        }

        async function getRecipesAw(){
            const IDs = await getIds;
            console.log(IDs);
            const recipe = await getRecipe(IDs[2]);
            console.log(recipe);
        }

        getRecipesAw();
    </script>
</body>

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

  async function getRecipesAw(){
            const IDs = await getIds;
            console.log(IDs);
            const recipe = await getRecipe(IDs[2]);
            console.log(recipe);
        }

प्रतीक्षा का उपयोग करने के लिए हमें एक async फ़ंक्शन की आवश्यकता होगी, हम एक वादा वापस कर सकते हैं, इसलिए उपयोग का वादा करें और वादे को अस्वीकार करने के लिए कैथ का उपयोग करें

उपरोक्त उदाहरण से:

 async function getRecipesAw(){
            const IDs = await getIds;
            const recipe = await getRecipe(IDs[2]);
            return recipe;
        }

        getRecipesAw().then(result=>{
            console.log(result);
        }).catch(error=>{
            console.log(error);
        });

0

कॉलबैक नरक से बचने का एक तरीका एफआरपी का उपयोग करना है जो कि आरएक्स का "उन्नत संस्करण" है।

मैंने हाल ही में एफआरपी का उपयोग करना शुरू कर दिया है क्योंकि मुझे इसका एक अच्छा कार्यान्वयन मिला है जिसे Sodium( http://sodium.nz/ ) कहा जाता है ।

एक विशिष्ट कोड इस तरह दिखता है (Scala.js):

def render: Unit => VdomElement = { _ =>
  <.div(
    <.hr,
    <.h2("Note Selector"),
    <.hr,
    <.br,
    noteSelectorTable.comp(),
    NoteCreatorWidget().createNewNoteButton.comp(),
    NoteEditorWidget(selectedNote.updates()).comp(),
    <.hr,
    <.br
  )
}

selectedNote.updates()एक है Streamजो आग अगर selectedNode(जो एक Cell) परिवर्तन है, NodeEditorWidgetतो इसी के अनुसार अद्यतन करता है।

तो, की सामग्री के आधार पर selectedNode Cell, वर्तमान में संपादित किया Noteजाएगा बदल जाएगा।

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

पूर्ण स्रोत कोड यहाँ है

निम्नलिखित सरल बनाएँ / प्रदर्शन / अद्यतन उदाहरण के लिए संक्षारक के ऊपर कोड स्निपेट:

यहां छवि विवरण दर्ज करें

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

StreamS और Cells का उपयोग करके सभी ईवेंट हैंडलिंग का ध्यान रखा जाता है । ये एफआरपी अवधारणाएं हैं। कॉलबैक की केवल आवश्यकता होती है जहां FRP तर्क बाहरी दुनिया के साथ इंटरफेस करता है, जैसे उपयोगकर्ता इनपुट, संपादन पाठ, एक बटन दबाने, AJAX कॉल रिटर्न।

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

एफआरपी (जो कि आरएक्स का अधिक "सख्त" संस्करण है) एक डेटा प्रवाह ग्राफ का वर्णन करने का एक तरीका है, जिसमें नोड्स हो सकते हैं जिसमें राज्य होते हैं। घटनाएँ राज्य में नोड्स ( Cellएस कहा जाता है ) में परिवर्तन को ट्रिगर करती हैं ।

सोडियम एक उच्च क्रम FRP लाइब्रेरी है, जिसका अर्थ है कि flatMap/ switchआदिम का उपयोग करके रनटाइम पर डेटा प्रवाह ग्राफ को पुनर्व्यवस्थित किया जा सकता है।

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

एफआरपी का उपयोग करना, केवल उन कॉलबैक को रखा जाना चाहिए जो बाहरी दुनिया के साथ बातचीत का वर्णन करते हैं। दूसरे शब्दों में, डेटाफ़्लो का वर्णन एक कार्यात्मक / घोषणात्मक तरीके से किया जाता है जब कोई FRP फ्रेमवर्क (जैसे सोडियम) का उपयोग करता है, या जब कोई "FRP जैसे" फ्रेमवर्क (जैसे RX) का उपयोग करता है।

सोडियम जावास्क्रिप्ट / टाइपस्क्रिप्ट के लिए भी उपलब्ध है।


-3

यदि आपके पास कॉलबैक और नरक कॉलबैक के बारे में कोई ज्ञान नहीं है, तो कोई समस्या नहीं है। इसके अलावा, कॉल बैक और कॉल नर्क है। उदाहरण के लिए: नर्क कॉल बैक एक तरह से है जैसे हम एक क्लास के अंदर क्लास स्टोर कर सकते हैं। जैसा कि आपने सुना सी, सी ++ भाषा में नेस्टेड के बारे में। नेस्टेड मीन्स कि एक वर्ग दूसरे वर्ग के अंदर।


उत्तर अधिक उपयोगी होगा यदि इसमें कोड स्निपेट शामिल है जो यह दर्शाता है कि 'कॉलबैक नरक' क्या है और 'कॉलबैक नरक' निकालने के बाद Rx के साथ समान कोड स्निपेट
राफा

-4

Jazz.js https://github.com/Javanile/Jazz.js का उपयोग करें

यह इस तरह सरल है:

    // रन अनुक्रमिक कार्य जंजीर
    jj.script ([
        // पहला काम
        फ़ंक्शन (अगला) {
            // इस प्रक्रिया के अंत में दूसरे कार्य के लिए 'अगला' बिंदु है और इसे चलाएं 
            callAsyncProcess1 (अगले);
        },
      // दूसरा कार्य
      फ़ंक्शन (अगला) {
        // इस प्रक्रिया के अंत में 'अगला' कार्य को चलाने और इसे चलाने के लिए इंगित करता है 
        callAsyncProcess2 (अगले);
      },
      // तीर्थ कार्य
      फ़ंक्शन (अगला) {
        // इस प्रक्रिया के अंत में 'अगला' बिंदु (यदि है) 
        callAsyncProcess3 (अगले);
      },
    ]);


इस तरह अल्ट्रा कॉम्पैक्ट पर विचार github.com/Javanile/Jazz.js/wiki/Script-showcase
cicciodarkast
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.