Насколько я понимаю, не должно быть возможности ожидать такие функции, как void foo() async {}, потому что они не возвращают будущего, которого можно было бы ожидать. Но я заметил, что когда я назначаю их в поле FutureOr<void> Function(), их можно ожидать. Следующий пример печатает: PRE, FUNC, POST
import 'dart:async';
void func() async {
await Future.delayed(const Duration(seconds: 2));
print('FUNC');
}
Future<void> main() async {
final FutureOr<void> Function() t = func;
print('PRE');
await t();
print('POST');
}
Я ожидаю, что он напечатает: PRE, POST, FUNC
Потому что функцию func нельзя ждать (поскольку она возвращает void) и, следовательно, await t() не следует ждать завершения функции func.
Я наблюдал такое же поведение с final dynamic Function() t = func;
Я не уверен, предназначено ли такое поведение или я просто не понимаю недействительные асинхронные функции?
Не используйте await, если хотите пропустить задачу. Используйте Future.sync() или Future.microtask() в вашем случае. Документация
import 'dart:async';
void func() async {
await Future.delayed(const Duration(seconds: 2));
print('FUNC');
}
Future<void> main() async {
final FutureOr<void> Function() t = func;
print('PRE');
Future.microtask(t);
print('POST');
}
Используя await, вы говорите компилятору, что хотите подождать, пока какая-то задача не будет завершена, и неважно, void это или нет.
Оператор await можно использовать с любым объект и с выражением любого типа, кроме void (и это только потому, что тип void специально запрещен в большинстве контекстов, а не что-то особенное для await).
Функция async всегда возвращает будущее. Даже если объявленный тип возвращаемого значения — void. Объявление возвращаемого типа как void — это просто сигнал пользователям о том, что они не должны ожидать полезного значения, и это усложняет фактическое получение значения (из-за вышеупомянутых ограничений на использование void типизированных выражений).
На самом деле, все возвращаемые функции void возвращают значение (если только они не бросают). Это значение обычноnull, но это не обязательно.
Поскольку вы можете отменить использовать метод void foo() с int foo() в подклассе и присвоить int Function() переменной типа void Function(), компилятор на самом деле не может знать наверняка, что функция со статическим типом void ничего не возвращает. Таким образом, он даже не пытается применить его для функций, которые сами типизированы как возвращающие void.
Тип FutureOr<void> является супертипом void (и Future<void>), поэтому функциональный объект void Function() можно присвоить типу FutureOr<void> Function().
В общем, это позволяет вашему коду работать так, как вы видите.
await t() выполняет await над выражением со статическим типом FutureOr<void> и фактическим значением, которое является Future<void>, которое было возвращено вызовом func. Итак, await t() ждет, пока FUNC будет напечатано.
См. stackoverflow.com/a/66381710 для некоторой информации.
void Function()является подтипомFutureOr<void> Function(), поэтому первое можно заменить вторым.awaitнаFutureOr<void>тоже нормально. То, чтоawaitуспешно ожидает завершения асинхронных операций в функцииvoid, является артефактом того, какvoidработает в Dart (это обещание не использовать значение). Вероятно, вам следует считать это ошибкой и не полагаться на нее.