AsyncIterator
simplifies writing asynchronous iteration tasks, such as for-eaching an iterator.
/** @var Plugin $plugin */
$handler = new AsyncIterator($plugin->getScheduler());
AsyncIterator::forEach
traverses forward over an Iterator
type and notifies handlers in the order of insertion.
Handlers can be added to a forEach
task by feeding a Closure
to AsyncIterator::forEach()::as()
, having the signature function(TKey $key, TValue $value) : AsyncForeachResult
.
$handler->forEach(new ArrayIterator([1, 2]))
->as(function(int $key, int $value) : AsyncForeachResult{
echo "First ", $value;
return AsyncForeachResult::CONTINUE();
})
->as(function(int $key, int $value) : AsyncForeachResult{
echo "Second ", $value;
return AsyncForeachResult::CONTINUE();
});
First 1
Second 1
First 2
Second 2
By default, AsyncIterator::forEach
traverses over 10 entries each tick. This can be changed by overriding the default parameter values of the method.
$entries_per_tick = 4;
$sleep_time = 1; // in ticks
AsyncIterator::forEach(new InfiniteIterator(new ArrayIterator([1, 2, 3])), $entries_per_tick, $sleep_time)
->as(function(int $key, int $value) : AsyncForeachResult{
echo $value, ", ";
return AsyncForeachResult::CONTINUE();
});
# First Tick:
1, 2, 3, 1
# Second Tick:
2, 3, 1, 2
...
Completion listeners are triggered when a foreach task successfully completes. This is determined by the return value of Iterator::valid()
(i.e., $completed = !Iterator::valid()
) of the iterator that is passed to AsyncIterator::forEach
.
$handler->forEach(new ArrayIterator([1, 2, 3]))
->as(function(int $key, int $value) : AsyncForeachResult{
echo $value;
return AsyncForeachResult::CONTINUE();
})
->onCompletion(function() : void{ echo "Completed"; })
Handlers have the ability to either continue, interrupt or cancel the traversal by returning either AsyncForeachResult::CONTINUE()
, AsyncForeachResult::INTERRUPT()
or AsyncForeachResult::CANCEL()
respectively.
When interrupted, a forEach
task will not traverse the iterator anymore and notify interrupt listeners immediately.
However, when cancelled, a forEach
task will notify no listeners and immediately dispose the task away.
$handler->forEach(new ArrayIterator([1, 2, 3]))
->as(function(int $key, int $value) : AsyncForeachResult{
echo $value;
return $value === 2 ? AsyncForeachResult::INTERRUPT() : AsyncForeachResult::CONTINUE();
})
->onCompletion(function() : void{ echo "Completed"; })
->onInterruption(function() : void{ echo "Interrupted"; });
1
2
Interrupted
$handler->forEach(new ArrayIterator([1, 2, 3]))
->as(function(int $key, int $value) : AsyncForeachResult{
echo $value;
return AsyncForeachResult::CONTINUE();
})
->onCompletion(function() : void{ echo "Completed"; })
->onInterruption(function() : void{ echo "Interrupted"; });
1
2
3
Completed
Interruption of a forEach
task can also occur externally (outside the handler) by calling the interrupt()
method on the return value of forEach
.
$foreach_task = $handler->forEach(new ArrayIterator([1, 2, 3]))
->as(function(int $key, int $value) : AsyncForeachResult{
echo $value;
return AsyncForeachResult::CONTINUE();
})
->onCompletion(function() : void{ echo "Completed"; })
->onInterruption(function() : void{ echo "Interrupted"; });
TaskScheduler::scheduleDelayedTask(function() use($foreach_task) : void{
$foreach_task->interrupt();
}, ticks: 2);
1
2
Interrupted
A `forEach` task may be cancelled by calling the `cancel()` method on the return value of `forEach`, causing no interrupt or completion listeners to be notified.
$foreach_task = $handler->forEach(new ArrayIterator([1, 2, 3]))
->as(function(int $key, int $value) : AsyncForeachResult{
echo $value;
return AsyncForeachResult::CONTINUE();
})
->onCompletion(function() : void{ echo "Completed"; })
->onInterruption(function() : void{ echo "Interrupted"; });
TaskScheduler::scheduleDelayedTask(function() use($foreach_task) : void{
$foreach_task->cancel();
}, ticks: 2);
1
2