advance method
Moves time forward by duration, firing every timer that comes due.
Yields to the microtask queue between timers so an async callback can
make progress, which is what lets a single call drive debounce → request →
retry.
Implementation
Future<void> advance(Duration duration) async {
final target = _now.add(duration);
while (true) {
final due = _timers.where((timer) => !timer.due.isAfter(target)).toList()
..sort((a, b) => a.due.compareTo(b.due));
if (due.isEmpty) break;
final next = due.first;
_now = next.due;
_timers.remove(next);
next.fire();
await pumpMicrotasks();
}
_now = target;
await pumpMicrotasks();
}