2015-01-22 11 views
8

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

मुझे वादों के प्रवाह के माध्यम से निर्भरताओं का प्रबंधन करने के लिए एक अच्छा तरीका सोचने में कठिनाई हो रही है।

मेरे मौजूदा कोड मूल रूप से इस तरह दिखता है:

var doStuff = function() { 
    var dependency1 = null; 
    var dependency2 = null; 

    promise1() 
    .then(function (value) { 
    dependency1 = value; 

    return promise2() 
    .then(function (value) { 
     dependency2 = value; 

     return promise3(dependency1) 
     .then(successFunction); 
    }); 
    }) 
    .catch(function (err) { 
    cleanupDependingOnSystemState(err, dependency1, dependency2); 
    }); 
}; 

ध्यान दें कि dependency1 promise3 जब तक की जरूरत नहीं है, और त्रुटि हैंडलर निर्भरता के बारे में पता करने की जरूरत है कि।

मेरे लिए यह स्पेगेटी कोड की तरह लगता है (और मेरा वास्तविक कोड बहुत समानांतर प्रवाह प्रवाह से बहुत खराब है)। मैंने यह भी पढ़ा है कि एक के अंदर एक और वादा वापस कर रहा है। तो कॉलबैक एक एंटीपाटर है। क्या मैं जो करने की कोशिश कर रहा हूं उसे पूरा करने का एक बेहतर/साफ तरीका है?

+0

यह प्रोग्रामर.स्टैकएक्सchange.com के लिए शायद ईमानदार व्यक्ति होने के लिए बेहतर है। – 1252748

+0

क्या 'वादा 2' 'वादा 1' पर निर्भर करता है? कोड का तात्पर्य है, लेकिन यह थोड़ा अस्पष्ट है। – loganfsmyth

+0

हां, बाद में आने वाला कोई वादा कुछ पूर्व वादे/डेटा को पुनर्प्राप्त करने पर निर्भर करता है। –

उत्तर

8

मुझे वर्तमान में दोनों उत्तरों को अच्छा लेकिन बेकार प्रदान किया गया है। वे दोनों अच्छे हैं लेकिन ओवरहेड हैं मुझे नहीं लगता कि आपको होना चाहिए। यदि आप इसके बजाय प्रॉक्सी के रूप में वादे का उपयोग करते हैं तो आपको बहुत सारी चीजें मुफ्त में मिलती हैं।

var doStuff = function() { 
    var p1 = promise1(); 
    var p2 = p1.then(promise2); 
    var p3 = p1.then(promise3); // if you actually need to wait for p2 here, do. 
    return Promise.all([p1, p2, p3]).catch(function(err){ 
     // clean up based on err and state, can unwrap promises here 
    }); 
}; 

कृपया successFunction का उपयोग नहीं करते और इस तरह यह एक विरोधी पैटर्न है और जानकारी खो देता है। अगर आपको लगता है जैसे आप का उपयोग करने के successFunction आप लिख सकते हैं:

var doStuff = function() { 
    var p1 = promise1(); 
    var p2 = p1.then(promise2); 
    var p3 = p1.then(promise3); // if you actually need to wait for p2 here, do. 
    Promise.join(p1, p2, p3, successFunction).catch(function(err){ 
     // clean up based on err and state, can unwrap promises here 
    }); 
}; 

हालांकि, यह असीम भी बदतर है, क्योंकि यह उपभोक्ता संभाल त्रुटियों वे संभाल करने में सक्षम हो सकता नहीं दूँगा।

+0

मुझे लगता है कि यह 'आखिरकार' पकड़ नहीं होना चाहिए, अन्यथा सफलतापूर्वक सफलतापूर्वक – Esailija

+0

@Esailija में नहीं किया गया है, उसका मूल उदाहरण पकड़ लिया गया है, लेकिन अगर यह संसाधन सफाई है तो मैं सहमत हूं कि अंत में जाने का सही तरीका है। संभवतः एक डिस्पोजेर पैटर्न का उपयोग करने के लिए बेहतर या बेहतर एक 'डिस्पोज़र' –

+0

यह ठीक तरह का समाधान है जिसे मैं ढूंढ रहा था, मैंने एकाधिक पंजीकरण करने पर विचार नहीं किया था। फिर कॉलबैक (यह अब इतना स्पष्ट प्रतीत होता है)। मेरे पास करने के लिए बहुत सारे रिफैक्टरिंग हैं। धन्यवाद। –

1

यह सवाल code review के लिए अधिक उपयुक्त हो सकता है, लेकिन यहाँ मैं इसे कैसे दृष्टिकोण होता दिए गए इस उदाहरण है:

var doStuff = function() { 
    // Set up your promises based on their dependencies. In your example 
    // promise2 does not use dependency1 so I left them unrelated. 
    var dep1Promise = promise1(); 
    var dep2Promise = promise2(); 
    var dep3Promise = dependency1Promise.then(function(value){ 
    return promise3(value); 
    }); 

    // Wait for all the promises the either succeed or error. 
    allResolved([dep1Promise, dep2Promise, dep3Promise]) 
     .spread(function(dep1, dep2, dep3){ 

    var err = dep1.error || dep2.error || dep3.error; 
    if (err){ 
     // If any errored, call the function you prescribed 
     cleanupDependingOnSystemState(err, dep1.value, dep2.value); 
    } else { 
     // Call the success handler. 
     successFunction(dep3.value); 
    } 
}; 

// Promise.all by default just fails on the first error, but since 
// you want to pass any partial results to cleanupDependingOnSystemState, 
// I added this helper. 
function allResolved(promises){ 
    return Promise.all(promises.map(function(promise){ 
    return promise.then(function(value){ 
     return {value: value}; 
    }, function(err){ 
     return {error: err}; 
    }); 
    }); 
} 

allResolved के उपयोग की वजह से ही अपने कॉलबैक बारीकियों की है, यदि आप एक अधिक सामान्य था त्रुटि हैंडलर, तो आप बस सीधे Promise.all का उपयोग कर हल कर सकता है, या यहाँ तक:

var doStuff = function() { 
    // Set up your promises based on their dependencies. In your example 
    // promise2 does not use dependency1 so I left them unrelated. 
    var dep1Promise = promise1(); 
    var dep2Promise = promise2(); 
    var dep3Promise = dependency1Promise.then(function(value){ 
    return promise3(value); 
    }); 

    dep3Promise.then(successFunction, cleanupDependingOnSystemState); 
}; 
1

यह निश्चित रूप से then रों भीतर वादे वापस जाने के लिए एक antipattern, नेस्टेड वादों सपाट एक विशेषता है नहीं है वादा spec के।

यहाँ एक संभव पुनर्लेखन है, हालांकि मुझे यकीन है कि नहीं कर रहा हूँ यह क्लीनर है:

var doStuff = function() { 

    promise1() 
    .then(function (value1) { 

    return promise2() 
    .then(function (value2) { 

     return promise3(value1) 
     .then(successFunction) 
     .finally(function() { 
     cleanup(null, value1, value2); 
     }); 

    }) 
    .finally(function() { 
     cleanup(null, value1, null); 
    }); 

    }) 
    .finally(function() { 
    cleanup(null, null, null); 
    }); 

}; 

या परमाणु सफाई कार्यों के साथ एक और विकल्प,:

var doStuff = function() { 

    promise1() 
    .then(function (value1) { 

    return promise2() 
    .then(function (value2) { 

     return promise3(value1) 
     .then(successFunction) 
     .finally(function() { 
     cleanup3(value2); 
     }); 

    }) 
    .finally(function() { 
     cleanup2(value1); 
    }); 

    }) 
    .finally(function (err) { 
    cleanup1(err); 
    }); 

}; 

वास्तव में, मुझे लगता है कि वहाँ आप काफी नहीं है की तरह इसे साफ करने के लिए कर सकते हैं। वेनिला try/catch ईएस के साथ कार्यक्रम, सर्वोत्तम संभव पैटर्न इनके समान ही है।

+0

मुझे लगता है कि मुझे लगा है कि मुझे वादे के बारे में कुछ याद आ रहा है क्योंकि अधिकांश दस्तावेज उदाहरण बेहद साफ जंजीर रूप हैं। –

संबंधित मुद्दे