nodejs parallel callback design pattern

后端 未结 6 1831
日久生厌
日久生厌 2020-12-25 10:34

I\'m trying to find a good pattern to execute a bunch of parallel tasks.

Let me define some task to exemplify. Tasks a, b, c, d, e, f, g execute as

相关标签:
6条回答
  • 2020-12-25 10:47

    yeah, look at flow control module, like step, chain, or flow ~ and i think there is something like that in underscore.js too

    0 讨论(0)
  • 2020-12-25 10:50

    Try to look at step module and this article.

    0 讨论(0)
  • 2020-12-25 10:52

    You should check out Step ( https://github.com/creationix/step ). It's just over a hundred lines of code, so you can read the whole thing if needed.

    My preferred pattern looks something like this:

    
    function doABunchOfCrazyAsyncStuff() {
      Step (
        function stepA() {
          a(arg1, arg2, arg3, this); // this is the callback, defined by Step
        }
        ,function stepB(err, data) {
          if(err) throw err; // causes error to percolate to the next step, all the way to the end.  same as calling "this(err, null); return;"
          b(data, arg2, arg3, this);
        }
        ,function stepC(err, data) {
          if(err) throw err;
          c(data, arg2, arg3, this);
        }
        ,function stepDEF(err, data) {
          if(err) throw err;
          d(data, this.parallel());
          e(data, this.parallel());
          f(data, this.parallel());
        }
        ,function stepGGG(err, dataD, dataE, dataF) {
          if(err) throw err;
          var combined = magick(dataD, dataE, dataF);
          var group = this.group();  // group() is how you get Step to merge multiple results into an array
          _.map(combined, function (element) {
            g(element, group()); 
          });
        }
        ,function stepPostprocess(err, results) {
          if(err) throw err;
          var processed = _.map(results, magick);
          return processed; // return is a convenient alternative to calling "this(null, result)"
        }
        ,cb // finally, the callback gets (err, result) from the previous function, and we are done
      );
    }
    

    Notes

    • My example also uses the underscore library, "the tie to match JQuery's tux": http://documentcloud.github.com/underscore/
    • Naming each step function stepXXXXX is a good habit so that the stack traces are clear and readable.
    • Step lets you make powerful and elegant combinations of serial and parallel execution. These patterns are straightforward and comprehensible. If you need anything more complex like "when 3 of 5 of these methods completes, go to the next step", seriously RETHINK your design. do you really need such a complex pattern? (maybe you are waiting for a quorum set). Such a complex pattern deserves a function of it's own.
    0 讨论(0)
  • 2020-12-25 11:01

    What you actually want is a deferred pattern though like futures.

    function defer(f) {
        // create a promise.
        var promise = Futures.promise();
        f(function(err, data) {
            if (err) {
                // break it
                promise.smash(err);
            } else {
                // fulfill it
                promise.fulfill(data);
            }
        });
        return promise;
    }
    var da = defer(a), db = defer(b), dc = defer(c), dd = defer(d), de = defer(e), df = defer(f), dg = defer(g);
    
    // when a and b are fulfilled then call ab
    // ab takes one parameter [ra, rb]
    Futures.join(da, db).when(ab);
    Futures.join(db, dc).when(bc);
    // abc takes one parameter [ra, rb, rc]
    Futures.join(da, db, dc).when(abc);
    Futures.join(db, dd).when(bd);
    Futures.join(db, dc, dd).when(bcd);
    Futures.join(da, df).when(af);
    // where's e ?
    Futures.join(df,dg).when(fg);
    Futures.join(da,db,dc,dd,de,df,dg).fail(function() {
        console.log(":(");
    });
    
    0 讨论(0)
  • 2020-12-25 11:01

    nimble is another good choice.

    0 讨论(0)
  • 2020-12-25 11:06

    A very simple barrier just for this: https://github.com/berb/node-barrierpoints

    0 讨论(0)
提交回复
热议问题