Содержание Что важно: Код в Dart работает в одном треде выполнения. Если код занят долгими вычислениями или ожидает операцию I/O, то вся программа приостанавливается. Асинхронные операции позволяют вашей программе завершить другие задачи в ожидании завершения операции. Dart использует futures для представления результатов асинхронных операций. Для работы с futures можно также использовать async и await или Future API. Заметка Давайте рассмотрим пример кода, который может "заморозить" выполнение программы: Наша программа читает из файла новости за день, выводит их, затем выводит еще интересующую пользователя информацию: В данном примере проблема, в том, что все операции после вызова gatherNewsReports()будут ожидать, пока gatherNewsReports() вернет содержимое файла, сколько бы времени это не заняло. Если чтение файла займет много времени, то пользователь будет вынужден ждать в ожидании результатов лотерии, прогноза погоды и победителя недавней игры. Чтобы поддерживать отзывчивость приложения, авторы Dart используют асинхронную модель при определении функций, выполняющих потенциально дорогостоящую работу. Такие функции возвращают свое значение, используя futures. future — экземпляр класса Future<Т>, который представляет собой асинхронную операцию, возвращающую результат типа T. Если результат операции не используются, то тип future указывают Future<void>. При вызове функции, возвращающей future, происходит две вещи:  Для написания кода, зависящего от future, у вас есть два варианта: Ключевые слова async и await являются частью поддержки асинхронности в Dart. Они позволяют писать асинхронный код, который выглядит как синхронный код и не использует Future API. Асинхронная функция — это функция, перед телом которой находится ключевое слово async. Ключевое слово await работает только в асинхронных функциях. Следующий код имитирует чтение новостей из файла, используя async — await. Откройте DartPad с приложением, запустите и кликните CONSOLE, чтобы увидеть результат. Обратите внимание, что мы сначала вызываем printDailyNewsDigest(), но новости выводятся последними, даже если файл содержит только одну строку. Это происходит потому, что код, который считывает и печатает файл, выполняется асинхронно. В этом примере printDailyNewsDigest() выполняет вызов gatherNewsReports(), который является неблокирующим. Вызов метода gatherNewsReports() ставит в очередь работу, но не останавливает выполнение остальной части кода. Программа выводит номера лотереи, прогноз и счет бейсбольного матча; программа печатает новости после завершения их сбора gatherNewsReports(). Если gatherNewsReports() занимает некоторое время для завершения своей работы, ничего страшного не происходит: пользователь может читать другие вещи до того, как будет напечатан ежедневный дайджест новостей. Обратите внимание на возвращаемые типы. Возвращаемым типом функции gatherNewsReports() является Future<String>, что означает, что она возвращает future, которое завершается строковым значением. Функция printDailyNewsDigest(), которая не возвращает значение, имеет возвращаемый тип Future<void>. На следующей диаграмме показаны шаги выполнения кода.   Обратите внимание, что асинхронная функция начинает выполняться сразу (синхронно). Функция приостанавливает выполнение и возвращает незавершенное future при достижении первого появления любого из следующих действий: Скорее всего вы хотели бы "отловить" ошибку выполнения функции, возвращающей future. В асинхронных функциях можно обрабатывать ошибки с помощью try-catch: Блок try-catch с асинхронным кодом ведет себя так же, как и с синхронным кодом: если код в блоке try создает исключение, выполняется код внутри catch. Можно использовать несколько выражений await, чтобы убедиться, что каждая инструкция завершается перед выполнением следующей: expensiveB() функция не выполняется, пока expensiveA() завершится, и так далее. До того, как async и await были добавлены в Dart 1.9, вы должны были использовать Future API. Вы и сейчас можете встретить использование Future API в старом коде и в коде, который нуждается в большей функциональности, чем async–await может предложить. Чтобы написать асинхронный код с помощью Future API, используйте метод then() для регистрации обратного вызова. Этот обратный вызов сработает, когда future завершится. Следующий код имитирует чтение новостей из файла, используя Future API. Откройте DartPad с приложением, запустите и кликните CONSOLE, чтобы увидеть результат. Обратите внимание, что мы сначала вызываем printDailyNewsDigest(), но новости выводятся последними, даже если файл содержит только одну строку. Это происходит потому, что код, который считывает и печатает файл, выполняется асинхронно. Это приложение выполняется следующим образом: Также код внутри then() может использовать фигурные скобки: Необходимо указать аргумент колбэка в then(), даже если future имеет тип Future<void>. По соглашению неиспользуемый аргумент определяется через _ (подчеркивание). Используя Future API, можно отловить ошибку с помощью catchError(): Если новости недоступны для чтения, то код выше выполняется следующим образом: Как и then(), catchError() возвращает новую future, которое завершается возвращаемым значением колбэка. Для погружения в тему читайте Futures and Error Handling. Рассмотрим три функции: expensiveA(), expensiveB(),expensiveC(), — которые возвращают future. Вы можете вызывать их последовательно (одна функция запускается после завершения предыдущей), или вы можете запустить их все одновременно и сделать что-то, как только все значения вернутся. Интерфейс Future достаточно гибок, чтобы реализовать оба варианта использования. Цепочка вызовов функций с помощью then()
Когда функции, возвращающие future, должны выполняться по порядку, используйте "цепочку" из then(): Вложение колбэков тоже работает, но его сложнее читать. (прим. http://callbackhell.com/) Ожидание завершения нескольких futures с помощью Future.wait()
Если порядок выполнения функций не важен, можно использовать Future.wait(). Когда вы для функции Future.wait() указываете список futures, как параметры, она сразу возвращает future. Эта future не завершится, пока не завершатся все указанные futures. Данная future завершится списком результатов всех указанных futures. Если вызов любой из функций завершается ошибкой, то и future, возвращаемая Future.wait(), также завершается ошибкой. Используйте catchError(), чтобы отловить эту ошибку. Dart 2. Асинхронное программирование: потоки данных Разработчик