Skip site navigation (1)Skip section navigation (2)

FreeBSD Manual Pages


home | help
Mojo::IOLoop::Delay(3)User Contributed Perl DocumentatioMojo::IOLoop::Delay(3)

       Mojo::IOLoop::Delay - Promises/A+ and flow-control helpers

	 use Mojo::IOLoop::Delay;

	 # Synchronize multiple	non-blocking operations
	 my $delay = Mojo::IOLoop::Delay->new;
	 $delay->steps(sub { say 'BOOM!' });
	 for my	$i (1 .. 10) {
	   my $end = $delay->begin;
	   Mojo::IOLoop->timer($i => sub {
	     say 10 - $i;

	 # Sequentialize multiple non-blocking operations

	   # First step	(simple	timer)
	   sub ($delay)	{
	     Mojo::IOLoop->timer(2 => $delay->begin);
	     say 'Second step in 2 seconds.';

	   # Second step (concurrent timers)
	   sub ($delay,	@args) {
	     Mojo::IOLoop->timer(1 => $delay->begin);
	     Mojo::IOLoop->timer(3 => $delay->begin);
	     say 'Third	step in	3 seconds.';

	   # Third step	(the end)
	   sub ($delay,	@args) {
	     say 'And done after 5 seconds total.';

       Mojo::IOLoop::Delay adds	flow-control helpers to	Mojo::Promise, which
       can help	you avoid deep nested closures that often result from
       continuation-passing style.

	 use Mojo::IOLoop;

	 # These deep nested closures are often	referred to as "Callback Hell"
	 Mojo::IOLoop->timer(3 => sub ($loop) {

	   say '3 seconds';
	   Mojo::IOLoop->timer(3 => sub	($loop)	{

	     say '6 seconds';
	     Mojo::IOLoop->timer(3 => sub ($loop) {

	       say '9 seconds';


       The idea	behind Mojo::IOLoop::Delay is to turn the nested closures
       above into a flat series	of closures. In	the example below, the call to
       "begin" creates a code reference	that we	can pass to "timer" in
       Mojo::IOLoop as a callback, and that leads to the next closure in the
       series when executed.

	 use Mojo::IOLoop;

	 # Instead of nested closures we now have a simple chain of steps
	 my $delay = Mojo::IOLoop->delay(
	   sub ($delay)	{ Mojo::IOLoop->timer(3	=> $delay->begin) },
	   sub ($delay)	{
	     say '3 seconds';
	     Mojo::IOLoop->timer(3 => $delay->begin);
	   sub ($delay)	{
	     say '6 seconds';
	     Mojo::IOLoop->timer(3 => $delay->begin);
	   sub ($delay)	{ say '9 seconds' }

       Another positive	side effect of this pattern is that we do not need to
       call "start" in Mojo::IOLoop and	"stop" in Mojo::IOLoop manually,
       because we know exactly when our	chain of "steps" has reached the end.
       So "wait" in Mojo::Promise can stop the event loop automatically	if it
       had to be started at all	in the first place.

       Mojo::IOLoop::Delay inherits all	attributes from	Mojo::Promise.

       Mojo::IOLoop::Delay inherits all	methods	from Mojo::Promise and
       implements the following	new ones.

	 my $cb	= $delay->begin;
	 my $cb	= $delay->begin($offset);
	 my $cb	= $delay->begin($offset, $len);

       Indicate	an active event	by incrementing	the event counter, the
       returned	code reference can be used as a	callback, and needs to be
       executed	when the event has completed to	decrement the event counter
       again. When all code references generated by this method	have been
       executed	and the	event counter has reached zero,	"steps"	will continue.

	 # Capture all arguments except	for the	first one (invocant)
	 my $delay = Mojo::IOLoop->delay(sub ($delay, $err, $stream) { ... });
	 Mojo::IOLoop->client({port => 3000} =>	$delay->begin);

       Arguments passed	to the returned	code reference are spliced with	the
       given offset and	length,	defaulting to an offset	of 1 with no default
       length. The arguments are then combined in the same order "begin" was
       called, and passed together to the next step.

	 # Capture all arguments
	 my $delay = Mojo::IOLoop->delay(sub ($delay, $loop, $err, $stream) { ... });
	 Mojo::IOLoop->client({port => 3000} =>	$delay->begin(0));

	 # Capture only	the second argument
	 my $delay = Mojo::IOLoop->delay(sub ($delay, $err) { ... });
	 Mojo::IOLoop->client({port => 3000} =>	$delay->begin(1, 1));

	 # Capture and combine arguments
	 my $delay = Mojo::IOLoop->delay(sub ($delay, $three_err, $three_stream, $four_err, $four_stream) { ...	});
	 Mojo::IOLoop->client({port => 3000} =>	$delay->begin);
	 Mojo::IOLoop->client({port => 4000} =>	$delay->begin);

	 $delay	= $delay->pass;
	 $delay	= $delay->pass(@args);

       Shortcut	for passing values between "steps".

	 # Longer version

	 $delay	= $delay->steps(sub {...}, sub {...});

       Sequentialize multiple events, every time the event counter reaches
       zero a callback will run, the first one automatically runs during the
       next reactor tick unless	it is delayed by incrementing the event
       counter.	This chain will	continue until there are no remaining
       callbacks, a callback does not increment	the event counter or an
       exception gets thrown in	a callback. Finishing the chain	will also
       result in the promise being fulfilled, or if an exception got thrown it
       will be rejected.

       Mojolicious, Mojolicious::Guides, <>.

perl v5.32.1			  2020-12-07		Mojo::IOLoop::Delay(3)


Want to link to this manual page? Use this URL:

home | help