javascript - एकाधिक अनजान कॉलबैक को संभालने के लिए जावास्क्रिप्ट फ़ंक्शन




function recursion (2)

मेरे पास एक परिदृश्य है जहां मैं एक हेन्डलर फ़ंक्शन में 2 या अधिक फ़ंक्शंस (पैरामीटर के रूप में) भेजना चाहता हूं, और उस हैंडलर फ़ंक्शन को पिछले फ़ंक्शन के लिए कॉलबैक फ़ंक्शन के रूप में प्रत्येक पारित फ़ंक्शन को निष्पादित करना होगा।

यहां फ़ंक्शन के एक सामान्य अवधारणा है जो मैं लिखने का प्रयास कर रहा हूं:

function functionChain() {
   // MAKE SURE WE HAVE AT LEAST 1 PARAMETER
   if ( arguments.length < 1 ) { return; }

   // for each parameter, call it (as a function)
   for ( var i=0; i<arguments.length; i++) {
     if ( typeof arguments[i] === 'function' ) {    
       call arguments[i];
     }
   }
}
// example
functionChain( function1, function2, function3 );

... तो ऊपर दिए गए कोड में, प्रत्येक फ़ंक्शन को उत्तराधिकार में बुलाया जाएगा।

जहां मैं फंस रहा हूं वह है कि प्रत्येक कॉल को कॉलबैक के रूप में कैसे व्यवहार करना चाहिए, जब पिछले फ़ंक्शन को पूरा किया जाए।

जिस तरह से मैं उससे संपर्क करता हूं, वह है एक चर (सादगी के लिए, केवल एक वैश्विक चर नामित functionChainComplete कहने देता है), और अगले समारोह को लॉन्च करने के लिए प्रतीक्षा करें - और निश्चित रूप से, मैं जो फ़ंक्शन लिखता हूं, वह functionChainComplete true को सेट करेगा। तो, ऐसा कुछ:

// set global var for tracking
var functionChainComplete;

function functionChain() {
   // MAKE SURE WE HAVE AT LEAST 1 PARAMETER
   if ( arguments.length < 1 ) { return; }

   // SET GLOBAL VAR TO FALSE
   functionChainComplete = true;

   // for each parameter, call it (as a function)
   for ( var i=0; i<arguments.length; i++) {
     if ( typeof arguments[i] === 'function' ) {    
       if ( functionChainComplete == true ) {
         // call the next function and wait for true again
         functionChainComplete = false;
         call arguments[i];
       } else {
         // try again in 50 ms (maybe setTimeout)?
       }
     }
   }
}

function1() { 
    // do something, and when done, reset functionChainComplete
    functionChainComplete = true;
}

function2() { 
    // do something, and when done, reset functionChainComplete
    functionChainComplete = true;
}

function3() { 
    // do something, and when done, reset functionChainComplete
    functionChainComplete = true;
}

// example
functionChain( function1, function2, function3 );

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


कहें कि आपके पास कुछ फ़ंक्शन है, double , जो तर्क, x , और कॉलबैक लेता है, k

const double = (x, k) =>
  k(x * 2)
  
double(2, console.log) // 4
double(3, console.log) // 6

अब कहते हैं कि हम इसे एक पंक्ति में 3 गुना चलाना चाहते हैं

const double = (x, k) =>
  k(x * 2)
      
const tripleDouble = (x, k) =>
  double(x, y =>
    double(y, z =>
      double(z, k)))
      
tripleDouble(2, console.log) // 16
tripleDouble(3, console.log) // 24

लेकिन निश्चित रूप से हमें प्रत्येक निरंतरता ( y => ... , और z => ... ) को स्थिर रूप से कोडित करना था। हम इस कार्य को एक चर राशि (एरे) के साथ कैसे कार्य करेंगे?

const double = (x, k) =>
  k(x * 2)
  
const composek = (...fs) => (x, k) =>
  fs.reduce((acc, f) =>
    k => acc(x => f(x, k)), k => k(x)) (k)
  
const foo = composek(double, double, double)

foo(2, console.log) // 16
foo(3, console.log) // 24

यह कुछ अमूर्त के लिए परिपक्व है, और मेरे पसंदीदा मोनद, द कंट्रीएशन मोनाद का परिचय देता है।

const Cont = f => ({
  runCont: f,
  chain: g =>
    Cont(k => f(x => g(x).runCont(k)))
})

Cont.of = x => Cont(k => k(x))

const composek = (...fs) => (x, k) =>
  fs.reduce((acc,f) =>
    acc.chain(x =>
      Cont(k => f(x,k))), Cont.of(x)).runCont(k)
      
const double = (x, k) =>
  k(x * 2)
  
const foo = composek(double, double, double)

foo(2, console.log) // 16
foo(3, console.log) // 24

यदि आपके पास ऐसे कार्य को बदलने की आजादी है जो आप चेन कर रहे हैं, तो इससे थोड़ा अधिक साफ हो जाता है - यहां, double में 1 पैरामीटर है और एक दूसरा तर्क के रूप में कॉलबैक लेने की बजाय एक Cont रिटर्न देता है

const Cont = f => ({
  runCont: f,
  chain: g =>
    Cont(k => f(x => g(x).runCont(k)))
})

Cont.of = x => Cont(k => k(x))

// simplified
const composek = (...fs) => (x, k) =>
  fs.reduce((acc,f) => acc.chain(f), Cont.of(x)).runCont(k)

// simplified
const double = x =>
  Cont.of(x * 2)
  
const foo = composek(double, double, double)

foo(2, console.log) // 16
foo(3, console.log) // 24

बेशक, यदि double वास्तव में अतुल्यकालिक था, तो यह एक ही काम करेगा

// change double to be async; output stays the same
const double = x =>
  Cont(k => setTimeout(k, 1000, x * 2))

const foo = composek(double, double, double)

foo(2, console.log) // 16
foo(3, console.log) // 24

कुछ इस तरह? (टिप्पणियां देखें, लेकिन काफी आत्म व्याख्यात्मक।)

function functionChain() {
    var args = arguments;

    // MAKE SURE WE HAVE AT LEAST 1 PARAMETER
    if ( args.length < 1 ) { return; }

    // Start the process
    var i = -1;
    go();

    function go() {
        // Pre-increment so we start at 0
        ++i;
        if (i < args.length) {
            // We have a next function, do it and continue when we get the callback
            args[i](go);
        }
    }
}

उदाहरण:

function functionChain() {
    var args = arguments;
    
    // MAKE SURE WE HAVE AT LEAST 1 PARAMETER
    if ( args.length < 1 ) { return; }

    // Start the process
    var i = -1;
    go();

    function go() {
        // Pre-increment so we start at 0
        ++i;
        if (i < args.length) {
            // We have a next function, do it and continue when we get the callback
            args[i](go);
        }
    }
}

// Just some functions for an example:
function a(callback) {
  console.log("a");
  callback();
}

function b(callback) {
  console.log("b");
  callback();
}

// Note this one is async
function c(callback) {
  setTimeout(function() {
    console.log("c");
    callback();
  }, 100);
}

function d(callback) {
  console.log("d");
  callback();
}

functionChain(a, b, c, d);

उस ने कहा, वादे के कारणों में से एक में संभवतः एसिंक कार्यों की रचना करने की अनुमति है यदि आपके कार्यों ने वादे वापस लिए हैं, तो हम मुहावरे को reduce :

function functionChain() {
    // Assumes the functions return promises (or at least thenables)
    Array.prototype.reduce.call(arguments, function(p, f) {
      return p.then(f);
    }, Promise.resolve());
}

function functionChain() {
    Array.prototype.reduce.call(arguments, function(p, f) {
      return p.then(f);
    }, Promise.resolve());
}

// Just some functions for an example:
function a(callback) {
  return new Promise(function(resolve) {
    console.log("a");
    resolve();
  });
}

function b(callback) {
  return new Promise(function(resolve) {
    console.log("b");
    resolve();
  });
}

// Note this one has a delay
function c(callback) {
  return new Promise(function(resolve) {
    setTimeout(function() {
      console.log("c");
      resolve();
    }, 100);
  });
}

function d(callback) {
  return new Promise(function(resolve) {
    console.log("d");
    resolve();
  });
}

functionChain(a, b, c, d);






callback