Почему вызывающая функция должна возвращать «будущее»?

#dart #async-await

#dart #асинхронное ожидание

Вопрос:

Я довольно новичок в Dart и пытался понять, почему вызывающая функция должна возвращать будущее? Я понимаю, почему вызываемая функция должна возвращать будущее, но не сама вызывающая функция. Кажется, это не имеет смысла и сбивает с толку логику. Например, скажем, я хотел:

 List<String> someFunct() async {
   final _res = await someFuture();
   return _res.toList();
}
  

Я не могу этого сделать, не обернув возврат вызывающей функции в будущее, которое затем распространяет эту асинхронную модель вверх по дереву вызовов. Вызывающая функция не является будущим, поэтому ей не нужно возвращать будущее.

Комментарии:

1. dart.dev/codelabs/…

2. В вашем примере someFunc невозможно вернуть значение вызывающей функции до завершения someFuture . Поскольку someFunc должны ждать, someFunc вызывающие тоже должны ждать. Может быть, вы думаете, что someFunc это может просто блокировать до someFuture завершения, но Dart является однопоточным в каждом изоляте. Если someFunc заблокировано, то someFuture никогда не будет разрешено. Может быть, вы думаете, что someFunc это может блокировать и разрешать someFuture разрешение, вращая собственный цикл событий, но теперь у вас будут вложенные циклы событий, которые, как правило, являются плохими новостями (например, они могут привести к неожиданному повторному входу).

Ответ №1:

Асинхронная функция — это функция, которая не завершает свою работу немедленно при вызове. Вот почему он возвращает a Future , который является объектом, который в конечном итоге сделает результат доступным.

Все функции должны возвращать что-то при вызове. Dart не поддерживает блокировку, когда функция просто останавливается посередине и позволяет другому коду выполняться до тех пор, пока он не будет готов к продолжению, потому что это требует наличия отдельных стеков, и он не может быть эффективно скомпилирован в JavaScript. Таким образом, асинхронная функция должна немедленно возвращать что-то, и это что-то является будущим.

Возврат будущего позволяет вызывающей функции ждать, пока результат не будет доступен. Он должен, если ему нужно использовать результат.

В вашем примере someFunct хочет вернуть список, который недоступен позже. Он не может просто вернуть список немедленно, потому что у него еще нет списка. Итак, она должна возвращать a Future<List<String>> .

Единственный случай, когда вам не нужно возвращать future из асинхронной функции, в противном случае, — это когда вызывающая функция не заботится о результате, или она получает результат каким-либо другим способом, скажем, добавляя его в коллекцию, когда он готов. Тогда вы можете просто вернуться void и не беспокоиться о будущем.

В подавляющем большинстве случаев ваши асинхронные функции должны возвращать будущее, потому что они хотят что-то вернуть, и это все, что у них есть, прежде чем будет готов реальный результат.

Комментарии:

1. Спасибо. Это имеет смысл.

2. @Irn не могли бы вы уточнить, скажем, добавляя его в коллекцию, когда он будет готов ? Я не понимаю вашу ссылку на добавление результата в коллекцию. Вы говорите о какой-то глобальной коллекции?

3. ДА. На самом деле я просто говорю о любом другом способе передачи результирующего значения из одного места в программе в другое, кроме его возврата. Помещение его в глобальную коллекцию или в коллекцию, которая была передана вместе с вызовом, или вызов некоторой глобальной функции для регистрации результата — это лишь некоторые из способов, которыми вы можете это сделать. Вызывающая функция также могла передать функцию обратного вызова (но тогда она действительно должна возвращать Future или Stream (в приведении обратный вызов будет вызываться более одного раза), потому что это канонический способ выполнения обратных вызовов в асинхронном коде).