How to organize groups of asynchronous functions without nesting (jquery $ .when. Then)

I have groups of asynchronous functions, where each group depends on the results of the previous group, but within the group the functions can execute / resolve in any order.

How can I call function groups sequentially without a nesting level for each group?

    function waste(secs)
    {
    	var prom=$.Deferred();
    	setTimeout(function(){
            $('body').append('<p>'+secs+'</p>');
            prom.resolve();
        }, secs*1000);
    	return prom;
    }
    
    $.when(
    	waste(5),
    	waste(4)
    ).then(function(){
    	$.when(
    		waste(3),
    		waste(2)
    	).then(function(){
    		$.when(
    			waste(1),
    			waste(0)
    		).then(function(){
    			$('body').append('<p>done</p>');
    		});
    	});
    });
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
Run codeHide result

Below is what I have found out so far, but in each section it has an uncomfortable indent return $.when(:

function waste(secs)
{
    var prom=$.Deferred();
    setTimeout(function(){
        $('body').append('<p>'+secs+'</p>');
        prom.resolve();
    }, secs*1000);
    return prom;
}
    
$.when(
    waste(5),
    waste(4)
).then(function(){
    return $.when(
        waste(3),
        waste(2)
    );
}).then(function(){
    return $.when(
        waste(1),
        waste(0)
    );
}).then(function(){
    $('body').append('<p>done</p>');
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
Run codeHide result

What will be the correct, best practice for a sequence of groups of asynchronous functions, where all methods in the group must end before the next group is executed?

I think, ideally, something like this is what I would like to work:

$.when(
    waste(5),
    waste(4)
).when(
    waste(3),
    waste(2)
).when(
    waste(1),
    waste(0)
).then(function(){
    $('body').append('<p>done</p>');
});
+4
source share
3

: ? , .


, .

​​ , , . callDef:

[func, arg1, arg2, arg3]

, :

[waste, 5]

:

function call(callDef) {
    return callDef[0].apply(null, callDef.slice(1));
}

​​ callDef, , callInParallel, callDefs:

[callInParallel, [callDef, callDef]]

[ callInParallel, [[waste, 5], [waste, 4]] ],

callInParallel :

function callInParallel(callDefs) {
    return $.when.apply($, callDefs.map(call));
}

, callDefs:

[
    [ callInParallel, [[waste, 5], [waste, 4]] ],
    [ callInParallel, [[waste, 3], [waste, 2]] ],
    [ callInParallel, [[waste, 1], [waste, 0]] ]
]

callDefs call callInParallel.

- callInSequence, callDef .

callInParallel , callDef: wait .then(). wait , .

, $.when, , -, :

function callInSequence(callDefs) {
    var wait = $.Deferred().resolve();
    return $.when.apply($, callDefs.map(function (callDef) {
        return wait = wait.then(function () {
            return call(callDef);
        });
    }));
}

, Def:

[
    callInSequence, [
        [ callInParallel, [[waste, 5], [waste, 4]] ],
        [ callInParallel, [[waste, 3], [waste, 2]] ],
        [ callInParallel, [[waste, 1], [waste, 0]] ]
    ]
]

:

function waste(secs) {
    var result = $.Deferred();
    setTimeout(function () {
        $('body').append('<div>'+secs+'</div>');
        result.resolve('done ' + secs);
    }, secs * 1000);
    return result.promise();
}
function call(callDef) {
    return callDef[0].apply(null, callDef.slice(1));
}
function callInParallel(callDefs) {
    return $.when.apply($, callDefs.map(call));
}
function callInSequence(callDefs) {
    var wait = $.Deferred().resolve();
    return $.when.apply($, callDefs.map(function (callDef) {
        return wait = wait.then(function () {
            return call(callDef);
        });
    }));
}
// ---------------------------------------------------------------------------

var everything = [
    callInSequence, [
        [ callInParallel, [[waste, 5], [waste, 4]] ],
        [ callInParallel, [[waste, 3], [waste, 2]] ],
        [ callInParallel, [[waste, 1], [waste, 0]] ]
    ]
];

call(everything).done(function () {
    $('<hr>').appendTo('body');
    $('<pre>', {text: JSON.stringify(arguments, null, 2)}).appendTo('body');
}).fail(function (error) {
    console.log(error);
});
$('<div>sequence has started...</div>').appendTo('body');
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.3/jquery.min.js"></script>
Hide result

:

  • jQuery 1.8+, , - , Deferreds 1.8.
  • -:

    var everything = [
        callInSequence, [
            [ callInSequence, [[waste, 5], [waste, 4]] ],
            [ callInParallel, [[waste, 3], [waste, 2]] ],
            [ callInSequence, [[waste, 1], [waste, 0]] ]
        ]
    ];
    
  • thisArg , (window). . , .bind(), callDef.
+3

, , ,

function waste(secs) {
    var prom = $.Deferred();
    setTimeout(function() {
      $('body').append('<p>' + secs + '</p>');
      prom.resolve();
    }, secs * 1000);
    return prom.promise();
  }
  // define error handler
var err = function err(e) {
  console.log(e)
};

$.when(
waste(5),
waste(4)
).then(function() {
  return $.when(
    waste(3),
    waste(2)
  ).fail(err);
}, err).then(function() {
  return $.when(
    waste(1),
    waste(0)
  ).fail(err);
}, err).then(function() {
  $('body').append('<p>done</p>');
}, err);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
Hide result
0

I assume that is $.whenequivalent Promise.all. In this case, what you are doing is right. I think that all you can really do to improve aesthetics is to join some of your lines:

$.when(waste(5),waste(4))
  .then(function() { return $.when(waste(3), waste(2)); })
  .then(function() { return $.when(waste(1), waste(0)); })
  .then(function(){
    $('body').append('<p>done</p>');
  }, errorHandler);

Is there a reason you are using jQuery? This can be done initially with Promises:

function append(secs) {
  return Promise(function(resolve, reject) {
    setTimeout(function(){
      $('body').append('<p>'+secs+'</p>');
      resolve();
    }, !isNaN(secs) && secs*1000);
  });
}

Promise.all([append(5), append(4)])
  .then(function() { return Promise.all([append(3), append(2)]); })
  .then(function() { return Promise.all([append(1), append(0)]); })
  .then(function() { return append('done'); }, errorHandler);
0
source

All Articles