cancelable_future 0.3.1 copy "cancelable_future: ^0.3.1" to clipboard
cancelable_future: ^0.3.1 copied to clipboard

Exploring the possibility of adding a cancelable future.

example/cancelable_future_example.dart

import 'dart:async';

import 'package:cancelable_future/cancelable_future.dart';

Future<void> main() async {
  await cancelableFutureTest();
}

Future<void> someOperation(int i) async {
  try {
    print('operation $i 0%');

    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('operation $i 25%');

    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('operation $i 50%');

    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('operation $i 75%');

    await Future<void>.delayed(const Duration(milliseconds: 100));
    print('operation $i 100%');
  } finally {
    print('operation $i finally');
  }
}

Future<void> someLongOperation() async {
  try {
    print('operation 1');
    await someOperation(1);

    print('operation 2');
    await someOperation(2);

    print('operation 3');
    await someOperation(3);

    print('operation 4');
    await someOperation(4);
  } finally {
    print('operations finally');
  }
}

final class Resource {
  Resource() {
    print('create resource');
  }

  void dispose() {
    print('dispose resource');
  }
}

Future<void> cancelableFutureTest() async {
  // Example 1:
  // Cancel by timer.
  //
  // operation 1
  // operation 1 0%
  // operation 1 25%
  // operation 1 50%
  // operation 1 75%
  // operation 1 100%
  // operation 1 finally
  // operation 2
  // operation 2 0%
  // operation 2 25%
  // operation 2 50%
  // --- cancel ---
  // operation 2 75%     <- nearest breakpoint
  // operation 2 finally
  // operations finally
  // main finally
  // result: null
  // result: canceled
  // exception: [AsyncCancelException] Async operation canceled
  // --- really canceled ---
  print('\nExample 1. Cancel by timer');
  final f1 = CancelableFuture(() async {
    try {
      await someLongOperation();

      return 'result';
    } finally {
      print('main finally');
    }
  });

  final cancelfuture = Future<void>.delayed(
    const Duration(milliseconds: 650),
    () async {
      print('--- cancel ---');
      await f1.cancel();
      print('--- really canceled ---');
    },
  );

  print('result: ${await f1.orNull}');
  print('result: ${await f1.onCancel(() => 'canceled')}');
  try {
    print(await f1);
  } on AsyncCancelException catch (error) {
    print('exception: [${error.runtimeType}] $error');
  }
  await cancelfuture; // Will really be canceled much later.

  // Example 2:
  // Cancel by timeout.
  //
  // operation 1
  // operation 1 0%
  // operation 1 25%
  // operation 1 50%
  // operation 1 75%
  // --- timeout ---
  // operation 1 100%
  // operation 1 finally
  // operation 2         <- function - don't stop, do the synchronized part
  // operation 2 0%      <- nearest breakpoint
  // operation 2 finally
  // operations finally
  // main finally
  // result: timeout
  // result: null
  // result: canceled
  // exception: [AsyncCancelByTimeoutException]
  //   Async operation canceled by timeout: 0:00:00.350000
  print('\nExample 2. Cancel by timeout');
  final f2 = CancelableFuture(() async {
    try {
      await someLongOperation();

      return 'result';
    } finally {
      print('main finally');
    }
  });

  final f2t = f2.timeout(
    const Duration(milliseconds: 350),
    cancelOnTimeout: true,
    onTimeout: () {
      print('--- timeout ---');
      return 'timeout';
    },
  );
  print('result: ${await f2t}');
  print('result: ${await f2.orNull}');
  print('result: ${await f2.onCancel(() => 'canceled')}');
  try {
    print(await f2);
  } on AsyncCancelException catch (error) {
    print('exception: [${error.runtimeType}] $error');
  }

  // Example 3:
  // Problem: If the code is not prepared to be canceled, resources may leak
  // out.
  //
  // create resource
  // safe async code without exceptions
  // --- cancel ---
  // exception: [AsyncCancelException] Async operation canceled
  print('\nExample 3. If the code is not prepared to be canceled,'
      ' resources may leak out');

  Future<void> safeAsyncCodeWhereNoExceptionsAreExpected() async {
    print('safe async code without exceptions');
    await Future<void>.delayed(const Duration(milliseconds: 100));
    await Future<void>.delayed(const Duration(milliseconds: 100));
  }

  Future<void> fairlyCommonThirdPartyCode() async {
    final resource = Resource();

    await safeAsyncCodeWhereNoExceptionsAreExpected();

    try {
      print('code that may have exceptions');
    } finally {
      resource.dispose();
    }
  }

  final f3 = CancelableFuture(() async {
    await fairlyCommonThirdPartyCode();
    return 'result';
  });

  Future<void>.delayed(
    const Duration(milliseconds: 50),
    () {
      print('--- cancel ---');
      f3.cancel();
    },
  );

  try {
    await f3;
  } on AsyncCancelException catch (error) {
    print('exception: [${error.runtimeType}] $error');
  }
}
0
likes
130
pub points
14%
popularity

Publisher

verified publisheryet-another.dev

Exploring the possibility of adding a cancelable future.

Repository (GitHub)
View/report issues

Documentation

API reference

License

BSD-3-Clause (LICENSE)

Dependencies

meta

More

Packages that depend on cancelable_future