Ответ
В Dart Future представляет отложенное вычисление или асинхронную операцию. Я создаю их несколькими способами в зависимости от задачи.
1. Использование конструкторов класса Future
Это низкоуровневые конструкторы для ручного создания Future.
-
Future(): Обертывает синхронную или асинхронную операцию, выполняемую в event loop.Future<int> heavyCalculation() { return Future(() { // Имитация долгой синхронной операции int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } return result; // Будет обернуто в завершенный Future }); } -
Future.delayed(): Создает Future, который завершается с результатом функции после задержки. Часто используется для имитации сетевых запросов или таймеров.Future<String> fetchUserData() { return Future.delayed( const Duration(seconds: 2), () => '{"name": "John"}', // Эта функция выполнится через 2 секунды ); } -
Future.value(): Немедленно создает завершенный успешный Future с заданным значением. Полезно в тестах или для возврата кэшированных данных.Future<Config> loadConfig() { if (_cachedConfig != null) { return Future.value(_cachedConfig!); // Немедленный возврат } return _fetchFromNetwork(); } -
Future.error(): Немедленно создает завершенный Future с ошибкой.Future<void> validateLogin(String email) { if (!email.contains('@')) { return Future.error(FormatException('Invalid email')); } return _checkServer(); }
2. Использование async/await
Любая функция, помеченная ключевым словом async, автоматически возвращает Future. Это самый частый способ в production-коде.
Future<List<Post>> fetchPosts() async {
// `await` приостанавливает выполнение функции, но не потока.
final response = await http.get(Uri.parse('https://api.example.com/posts'));
if (response.statusCode == 200) {
return (jsonDecode(response.body) as List).map((e) => Post.fromJson(e)).toList();
} else {
throw Exception('Failed to load posts');
}
}
// Функция fetchPosts возвращает Future<List<Post>>
3. Преобразование Stream в Future
Методы first, last, single, elementAt и reduce у Stream возвращают Future.
Future<int> getFirstValueFromStream(Stream<int> stream) {
return stream.first; // Возвращает Future<int>
}
Выбор способа: Для работы с внешними ресурсами (сеть, БД) я использую async-функции. Для создания отложенных задач или моков в тестах — конструкторы Future.delayed или Future.value.
Ответ 18+ 🔞
А, вот это уже интересно! Слушай, тут про эти ваши Future в Dart. Ну, типа, обещание какое-то, которое выполнится потом, когда захочет. Как сосед, который должен сотку, но вернёт её, только когда у него премия на работе или тёща помрёт. В общем, создавать их можно по-разному, смотри.
1. Через конструкторы — это как вручную собирать мебель из IKEA
Тут ты сам всё контролируешь, но и хуйню накосячить проще. Низкоуровневое такое колдунство.
-
Просто
Future(): Заворачиваешь какую-то долгую операцию, чтобы она не тормозила всё нахер. Типа, отдаёшь её в работу какому-то левому пулу, а сам идёшь пить кофе.Future<int> heavyCalculation() { return Future(() { // Представь, что тут какая-то пиздец какая тяжёлая математика int result = 0; for (int i = 0; i < 1000000000; i++) { result += i; } return result; // И вот этот результат засунут в Future и вернут тебе }); }По сути говоришь: "Эй, выполни-ка это где-нибудь на фоне, а я потом заберу".
-
Future.delayed(): О, это классика! Создаёшь Future, который тупо будет спать заданное время, а потом что-то сделает. Идеально, чтобы сымитировать сетевой запрос, который всегда тормозит, как чёрт.Future<String> fetchUserData() { return Future.delayed( const Duration(seconds: 2), // Поспи, сука, две секунды () => '{"name": "John"}', // А потом проснись и верни эту хуйню ); }Прям как мой интернет-провайдер — обещает высокую скорость, но только после ребута роутера через неопределённый промежуток времени.
-
Future.value(): А это для умников, которые всё уже посчитали. Future, который завершён сразу же, в момент создания. Как будто ты пообещал другу бутылку пива и тут же её ему сунул в руки. Никакой интриги!Future<Config> loadConfig() { if (_cachedConfig != null) { return Future.value(_cachedConfig!); // На, держи, не задерживай очередь! } return _fetchFromNetwork(); // А если нет в кэше, тогда иди, мучайся, как все. } -
Future.error(): А это — сразу дать по морде ошибкой. Не стал даже пытаться что-то делать, сразу — на тебе, получай исключение, завернутое в Future. Жестоко, но иногда нужно.Future<void> validateLogin(String email) { if (!email.contains('@')) { // Если email кривой return Future.error(FormatException('Invalid email')); // Пиздуй отсюда с таким email! } return _checkServer(); // Ладно, если email норм, проверим на сервере. }
2. Магия async/await — как будто пишешь синхронный код
Вот это, блядь, красота! Ставишь async у функции — и она автоматом начинает возвращать Future. Внутри используешь await перед другой асинхронной хуйнёй, и код выглядит так, будто он выполняется построчно. Хотя на самом деле всё хитрее, епта.
Future<List<Post>> fetchPosts() async {
// Тут `await` говорит: "Стой, блядь, на этом месте. Не иди дальше, пока не получишь ответ".
// Но главный поток при этом не блокируется, он может чатики в телеге проверять.
final response = await http.get(Uri.parse('https://api.example.com/posts'));
if (response.statusCode == 200) {
return (jsonDecode(response.body) as List).map((e) => Post.fromJson(e)).toList();
} else {
throw Exception('Failed to load posts'); // Если сервер лёг, кидаем ошибку
}
}
// Сама функция fetchPosts всё равно вернёт тебе Future<List<Post>>, это железно.
Это как заказать еду с доставкой (async функция) и ждать курьера у двери (await), но при этом ты можешь параллельно мыть посуду (рисовать UI), а не стоять как идиот, уставившись в глазок.
3. Выковыривание Future из Stream
Stream — это как труба, из которой данные прут потоком. А иногда тебе надо вытащить оттуда всего один кусок и завернуть его в Future. На помощь приходят методы вроде first.
Future<int> getFirstValueFromStream(Stream<int> stream) {
return stream.first; // Дай мне первый элемент из этого потока и заверни в Future, пожалуйста!
}
Сидишь, ждёшь, когда в трубе что-то появится, хватаешь первое, что вылезло, и довольный уходишь.
А теперь, блядь, главное: Если пишешь нормальный код и работаешь с сетью, базой или файлами — юзай async/await, не еби мозг. Если надо в тестах что-то замокать или сделать таймер — Future.delayed или Future.value тебе в помощь. А если чувствуешь себя хакером и хошь покопаться в кишках — тогда конструкторы. Но без фанатизма, а то сам потом не разберёшься.