2010-12-21 14 views
5

क्या आप कृपया मुझे बता सकते हैं कि जावास्क्रिप्ट में वास्तव में बुनियादी प्रवाह नियंत्रण कैसे लिखना है? धन्यवाद।जावास्क्रिप्ट में मूल प्रवाह नियंत्रण

flow([ 

    function(callback) { /* do something */ callback(); /* run next function */ }, 
    function(callback) { /* do something */ callback(); /* run next function */ }, 
    function(callback) { /* do something */ callback(); /* run next function */ }, 
    function(callback) { /* do something */ callback(); } 

], function() { 

    alert("Done."); 

}); 
+3

... क्या आप कृपया अधिक विस्तार से समझा सकते हैं कि आप क्या करना चाहते हैं? – deceze

+0

मैं इस प्रवाह नियंत्रण को लिखना चाहता हूं, लेकिन मुझे नहीं पता कि कैसे। मैंने बहुत सारे कोड के माध्यम से ब्राउज़ किया, लेकिन मुझे यह नहीं मिला। –

+0

क्या कार्य संभावित रूप से असीमित हैं? – slebetman

उत्तर

0
(function(){ 
    function a(cb) { alert('hi'); cb(); } 
    function b(cb) { alert('there'); cb(); } 
    function c(cb) { alert('replace alert with console.log for ease'); cb(); } 
    var done = function() { alert('done'); } 
    a(b(c(done))); 
})() 
0
// callback is a global function, I assume 

function flow(funcArr, funcEnd) {  
    for (var i = 0; i < funcArr.length; i++) { 
     funcArr[i](callback); 
    }  
    funcEnd(); 
} 

यह उन सभी कार्यों चलाना शामिल है।

+0

लेकिन निर्दिष्ट क्रम में नहीं यदि वे असीमित हैं। – slebetman

+0

हां। मैं उन कार्यों को निर्दिष्ट क्रम में चलाने के लिए झुकाऊंगा। –

+0

@slebetman जिस तरह से मेरा कोड काम करता है यह है कि सभी कार्य तुल्यकालिक हैं। –

7

क्या इस काम को कुछ पसंद आएगा?

function flow(fns, last) { 
    var f = last; 
    for (var i = fns.length - 1; i >= 0; i--) 
     f = makefunc(fns[i], f); 
    f(); 
} 

function makefunc(f, g) { 
    return function() { f(g) } 
} 
+0

यह उत्तर छोटा, सुरुचिपूर्ण और सही है। –

+0

var f = आखिरी बार क्या करता है? – qwertymk

+1

@qwertymk: 'f' को 'अंतिम' के साथ प्रारंभ किया गया है और वहां से बनाया गया है। सबसे पहले, यह 'आखिरी 'है। फिर, यह 'मेकफनक (एफएनएस [एन -1], आखिरी)' है, उसके बाद 'मेकफनक (एफएनएस [एन -2], मेकफनक (एफएनएस [एन -1], आखिरी))', आदि .. यह एक इमारत की तरह है [विपक्ष सूची] (http://en.wikipedia.org/wiki/Cons), जहां 'मेकफनक' "विपक्ष" है, और 'अंतिम' "शून्य" है। –

1

मैं हाल ही में एक परियोजना में काफी है कि का एक सा कर रहा हूँ। मैंने इसे प्रबंधित करने में मदद के लिए कुछ कोड लिखा है। कोड यहाँ है। आप bundledAsync को "कॉल" पैरामीटर और "बंडल कॉलबैक" पैरामीटर वाले ऑब्जेक्ट को पास करते हैं। कॉल पैरामीटर उस कार्य का प्रतिनिधित्व करने वाले objets की एक सरणी है जिसे आप कॉल करना चाहते हैं। एफएन param में, आप वास्तविक पैरामीटर का संदर्भ संग्रहीत करते हैं। "Args" param में, आप अपने तर्क संग्रहीत करते हैं। आपके द्वारा पारित किए गए प्रत्येक कार्य का अंतिम तर्क कॉलबैक होना चाहिए, जिसे कॉल किया जाना चाहिए।

मैं अपने कोड को दस्तावेज करने और इसे दूसरों के लिए उपयोगी बनाने में दुखी हूं, लेकिन यह वास्तव में मेरे लिए वास्तव में उपयोगी है। मुझे संदेह है कि किसी और ने कुछ ऐसा लिखा है, शायद सही ढंग से प्रलेखित। अगर आपको यह नहीं मिल रहा है, और इसे समझने में मदद की ज़रूरत है, तो मुझे बताएं।

/** 
    This is a way to submit multiple async calls, and be notified when they've all finished 

    <pre> 

    NameSpace.bundledAsync({ 
    calls:[ 
     { 
     fn: service.getGroups, 
     args: [ 
      function(listsArg){ 
      listsSummary = listsArg; 
      } 
     ], 
     calls: function(){return UNAB.Util.makeArray(listsSummary, function(list){ 
      return { 
      fn: service.getGroup, 
      args: [list.id, function(resp){listsDetail.push(resp)}] 
      } 
     })} 
     } 
    ], 
    bundleCallback: function(){ 
     callback(listsDetail) 
    } 
    }); 

    </pre> 

    @class bundledAsync 
    @static 

*/ 

NameSpace.bundledAsync = function(options){ 

    var callbacksLeft = 0; 
    var calls = $.grep(options.calls, function(call){return call}); 


    if(options.hasOwnProperty("bundleCallback") && typeof options.bundleCallback != "function"){ 
     throw new Error("bundleCallback, passed to bundledAsync, must be a function."); 
    } 

    if(options.chain){ // if this is true, sibling calls will run in succession, not in parallel 
     calls.reverse(); 
     var newCalls = [calls.pop()]; 
     var lastCall = newCalls[0]; 
     while(calls.length > 0){ 
     if(lastCall.calls){ 
      throw new Error("You can't nest calls if you're in chain mode"); 
     } 
     lastCall.calls = [calls.pop()]; 
     lastCall = lastCall.calls[0]; 
     } 
     calls = newCalls; 
    } 

    var decrimentCallbacksLeft = function(){ 
     if(options.name){ 
     // log.debug("Starting decrimentCallbacksLeft for: " + options.name + ". Decrimenting callbacksLeft to: " + (callbacksLeft - 1)); 
     } 
     if(--callbacksLeft == 0 && options.bundleCallback){ 
     // log.debug("No callbacks left. Calling bundleCallback for name: " + options.name); 
     options.bundleCallback(); 
     } 
    } 

    var doCalls = function(callsToDo){ 

     if(typeof callsToDo == "function"){ 
     callsToDo = callsToDo(); 
     }else{ 
     callsToDo = $.extend(true, [], callsToDo);// in case we want to reuse the calls 
     } 

     // right away, return if the calls are empty 
     // check to make sure callbacksLeft == 0, because 
     // we may be dealing with nested calls 
     if(callsToDo.length ==0 && callbacksLeft == 0){ 
     // log.debug("callsToDo is empty, so call the callback right away."); 
     options.bundleCallback(); 
     return null; 
     } 

     callbacksLeft += callsToDo.length; 
     $.each(callsToDo, function(index, call){ 
     var numFns = 0; 
     // // Look through the args searching for functions. 
     // // When one is found, wrap it with our own function. 
     // // This assumes that each function has exactly one 
     // // callback, and that each callback is called exactly once 
     // args can be a function which will return the args, 
     // that way, you don't have to determine the args for the function until the moment it's called 
     call.args = call.jitArgs? call.args():call.args; 
     $.each(call.args, function(index, arg){ 
      if(typeof arg === "function"){ 
      numFns++; 
      // Here's where we wrap the original function's callback 
      call.args[index] = function(){ 
       // when we get to this point, we know that the original function has totally completed, 
       // and we can call any functions chained to this one, or finish the whole process 
       arg.apply(null, arguments); // call the original callback 
       if(call.calls){ 
       // maybe we don't want to create the child calls until after 
       // the parent has returned. In that case, pass a function instead of an array 
       if(typeof call.calls === "function"){ 
        call.calls = call.calls(); 
       } 
       // if this call has any call of its own, send those out now 
       doCalls(call.calls); 
       } 
       decrimentCallbacksLeft(); 
      } 
      } 
     }); 
     if(numFns!=1){ 
      throw new Error("Each function passed to bundledAsync must have one and only one arg which is a function"); 
     } 
     // if(call.fn.length != call.args.length){ 
     // log.warn("The current function is being called with a different number of arguments that that with which it was declared. Should be: "+call.fn.length+", was: "+call.args.length+" \n" + call.fn.toString()); 
     // } 
     call.fn.apply(null, call.args); 
     }); 
    } 

    doCalls(calls); 
    } 
1

मैं के बारे में continuation-passing style पढ़ने की सलाह। ऐसा लगता है कि आपका लक्ष्य है, एक निरंतर तर्क लेने वाले कार्यों की एक सरणी दी गई है, उन्हें एक साथ श्रृंखलाबद्ध करें कि निरंतरता सरणी में अगले कार्य में आगे बढ़ती है।

function flow(funcArr, funcDone) { 
    function proceed(i) { 
     if (i < funcArr.length) { 
      return function() { 
       funcArr[i](proceed(i+1)); 
      } 
     } else { 
      return funcDone; 
     } 
    } 

    proceed(0)(); 
} 

संपादित करें:: Anon.'s answer छोटा और सरल है

यहां इस तरह के एक समारोह के एक कार्यान्वयन है।

यहाँ यह कैसे काम करता है: proceed(i) एक कॉलबैक जो मैं वें फ़ंक्शन को कॉल (या, funcDone, अगर कोई भी सरणी में छोड़ दिया जाता है) देता है। क्योंकि proceed(i) इसे करने के बजाए कॉलबैक देता है, हम proceed(i+1) का उपयोग contiunation फ़ंक्शन के रूप में कर सकते हैं।

नमूना उपयोग:

flow([ 

    function(cb) { print("Thing one"); cb(); }, 
    function(cb) { print("Thing two"); cb(); }, 
    function(cb) { print("Thing three"); cb(); }, 
    function(cb) { print("Thing four"); cb(); }, 

], function() { 

    print("Done."); 

}); 

अब cb(); कॉल में से एक को दूर करने का प्रयास करें। यह श्रृंखला तोड़ देगा, जो शायद आप वास्तव में क्या चाहते हैं। एक और अच्छी बात यह है कि, आप cb ले सकते हैं, इसे वैश्विक चर में घुमा सकते हैं, और प्रवाह को फिर से शुरू करने के लिए इसे बाद में कॉल कर सकते हैं।

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

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