
В данной серии статей я не буду касаться азов программирования на самом Dart, а коснусь вопросов асинхронности в Dart.
Библиотеки Dart полны функций, которые возвращают Future или Stream объекты. Эти функции асинхронны.
В документации читаем:
Future — подобен обещанию когда-то в будущем предоставить результат.
Stream — это способ получить последовательность значений, таких как, например, последовательность событий (поток).
Future и Stream входят в библиотеку dart:async, которую можно использовать как в скриптах веб-приложений, так и в скриптах, запускаемых из консоли.
Импортируем библиотеку так:
import 'dart:async';
Future
В библиотеках Dart полно функций возвращающих Future. Когда future-объект завершается (какая-то операция), его значение готово к использованию. Причем работать с Future можно разными способами.
Использовать async и await
Это, наверное, самый простой и понятный способ обработки future-объектов. Он очень похож на синхронный.
someFunction() async {
var someVar = await functionXXL();
if (someVar == someParam) {
// Делаем что-то.
} else {
// Делаем что-то.
}
}
В чем суть await: await ожидает возвращения результата асинхронной функции.
async функция (someFunction() — в нашем примере) фактически возвращает сразу, до того, как выполнятся асинхронные операции внутри нее, но возвращает она Future, т.е. возвращает «обещание» вернуть определенные значения позже, когда асинхронные процессы будут завершены.
Внутри функции с ключевым словом async мы можем запустить один или несколько асинхронных процессов. Другими словами конструкций await может быть много (пример из оригинальной документации):
runUsingAsyncAwait() async {
//...
var entrypoint = await findEntrypoint();
var exitCode = await runExecutable(entrypoint, args);
await flushThenExit(exitCode);
}
Важно обратить внимание на следующее:
1. await работает только внутри тела функции, которое предварено ключевым словом async.
2. await конструкции выполняются в том же логическом порядке, как они написаны. Т.е. пока не выполнился один await управление не передается следующему.
3. async функции всегда возвращают Future. Если мы не хотим, чтобы наша функция возвращала Future, можно использовать различные решения для этого, например, мы можем вызвать async функцию из другой (не async) функции.
Теперь давайте посмотрим, как происходит обработка ошибок в async функциях:
someFunc() async {
// какая-то логика
try {
await someObject.start();
} catch (e) {
// управление ошибками
}
}
Используем метод Future — then()
Этот вариант имеет воплощение более похожее на асинхронное. Рассмотрим на примере (пример из оригинальной документации):
HttpRequest.getString(url).then((String result) {
print(result);
}).catchError((e) {
// Обрабатываем или игнорируем ошибку.
});
В этом примере HttpRequest.getString(url) возвращает Future. Когда Future завершается, метод then() выполняет некоторый код, в нашем случае выводит строку в консоль. Обратите внимание на, что обработка ошибок в этом случае происходит в конструкции catchError.
Шаблон then().catchError() является сам по себе асинхронной версией try-catch.
Метод then() возвращает Future, обеспечивая удобный способ запуска нескольких асинхронных функций в определенном порядке. Если функция обратного вызова (callback), зарегистрированная в then(), возвращает Future, then() возвращает эквивалентный Future. Если callback возвращает значение любого другого типа, then() создает новый Future, который завершается с этим значением.
Опять пример из оригинальной документации:
Future result = costlyQuery();
return result.then((value) => expensiveWork())
.then((value) => lengthyComputation())
.then((value) => print('done!'))
.catchError((exception) => print('DOH!'));
Здесь мы видим «сцепление» нескольких .then().
Функции в этом примере отрабатывают в следующем порядке:
1. costlyQuery()
2. expensiveWork()
3. lengthyComputation()
Используем метод Future.wait()
Если нам нужно выполнить несколько асинхронных функций, а по окончании их выполнения выполнить некоторый код, можно использовать статический метод Future.wait(). Пример:
Future func1 = doSmth1();
Future func2 = doSmth2();
Future func3 = doSmth3();;
Future.wait([func1, func2, func3])
.then((List values) {
print('Отработали!');
});
Ссылки по теме
Асинхронное программирование Dart (eng): (ссылка 1, ссылка 2).
Также можно почитать: (ссылка 3, ссылка 4)
Я не гуру в Dart, поэтому буду очень благодарен за ваши замечания, уточнения и предложения. Спасибо за внимание.
rock
То есть, в плане
Future
/async
/await
, Dart абсолютно ничем не отличатся от JSPromise
(ES6) /async
/await
(ES7):degorov
Так создатели Dart изначально говорили, что внедряются только те фичи и только так, чтобы это всё потом можно было бы затранспайлить во вменяемый JS-код. А теперь, когда они официально дропнули dart vm в браузере, уж и подавно.
TheSteelRat
Да, только в Dart они уже есть в стабильной ветке, собраны в одном месте, работают и компилируются в JS. В родном JS они повсеместно придут ещё не скоро.
rock
В JS
async
/await
я использую больше года.Promise
— несколько лет. Babel, можно отдельно regenerator, traceur — ну да, совсем не скоро :)TheSteelRat
Тут смотря как сравнивать. Я вам говорю про «голые» языки без дополнительных тулзов. В тех средах где запускается Dart, stream/future/async/await работают из коробки. Вышеперечисленные фичи JS без компиляции мало где заработают.
rock
Да, Dart — это «голый» и не компилируемый в JS язык программирования, юмор оценил :)
kelegorm
Я понял так, что говорили о том, что Dart сам по себе имеет все фичи из коробки, и они работают. Когда ведется разработка с использованием дарта, все запускается в браузере Dartium, где дарт как раз не компилируется и работает нативно. А перед паблишем уже идет компиляция в js. Все из коробочки.
rock
Не понимаю. Я говорил только о том, что этот функционал в Dart и JS идентичен — а мне начинают доказывать, что это функционал есть Dart а в JS будет неизвестно когда, при том, что согласно новой стратегии развития Dart, в первую очередь, компилируемый в JS язык и с этой позиции ничем не отличается от грядущих стандартов JS, которые также где-то доступны из коробки, а где-то требуют полифилов и компиляции в старый синтаксис. Кроме, разве что, того, что повсеместное внедрение этих стандартов планируется, а Dart'a — нет.
kelegorm
Ну так-то да, текущая ситуация такова, что оба языка должны компилироваться в старый нормальный JS с какими-то костылями, и для языка, и для браузера.
Но разница есть, в пользу дарта следующая:
1. Разрабатывая на дарте, можно пропускать этап компиляции в JS (в Dartium отлаживаем же) — это экономия времени.
2. У дарта есть некая инфраструктура, ничуть не хуже node.js и npm, и многие считают даже более вревосходящей.
То есть, на данный момент, разработка на дарте будет несколько удобнее, чем на JS 6.
Но может я чего-то не знаю, и у JS 6 есть чем здесь ответить, поправьте меня в таком случае.
ko11ega
Компилировать в JS нужно только один раз перед выкладыванием кода в продакшн.
При разработке, внеся изменения в код, мы просто нажимаем F5 в Dartium и мгновенно можем увидеть работу новой версии кода.
Это очень убыстряет разработку.