onCancel method

  1. @override
void Function() onCancel(
  1. void callback()
)
override

Registers callback to run the moment the job accepts a cancellation, before the body itself learns about it.

Returns a function that unregisters it; callbacks run in the order they were registered, each once. This is how a cancellation reaches something that can really stop: a device's own cancel token, an HTTP client's abort, a subscription. Throws Cancelled if the job is already cancelled, and so does a registration made from a callback, which runs in a job cancelled by then. An error thrown by callback goes to onError and on to the job's answer; the cancellation itself is not affected and the other callbacks still run.

final token = CancelToken();
ctx.onCancel(token.cancel);
// The device stops by itself, and `join` waits for it to finish
// before the job ends and the next one starts.
await ctx.join(() => device.seek(position, cancelToken: token));

callback is synchronous, and only what it throws synchronously is caught: the future an async one returns is awaited by nobody, and its failure goes to the zone it happens to run in, past any observer. For something that stops asynchronously, hand the work to the core: ctx.onCancel(() => ctx.unattended(device.stop)).

See A token through onCancel and A stop that takes time on the cancellation page.

Implementation

@override
void Function() onCancel(void Function() callback) {
  throwIfFinished('register onCancel');
  throwIfCancelled();
  void guarded() {
    // A callback of the caller's, run from inside the core's own
    // cancellation: its error belongs to `notifyError`, not to whoever
    // happened to trigger the cancel.
    try {
      callback();
    } on Object catch (error, stackTrace) {
      if (error is StackOverflowError && _owner._outOfStack) {
        // Not `onError`, and above all not the zone, while the core
        // is unwinding a cascade that ran out of stack: see
        // `JobBase.whenCancelled`, which keeps the same rule for the
        // same reason.
        rethrow;
      }
      notifyError(error, stackTrace);
    }
  }

  return addCancelCallback(guarded);
}