Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего нужны Future?
Future — это объект, который представляет значение, которое может быть доступно сейчас или в будущем. Future используются для работы с асинхронными операциями, такими как сетевые запросы, загрузка файлов, доступ к базе данных. Это критично для создания отзывчивых приложений, которые не блокируют UI.
Проблема, которую решают Future
Синхронный (блокирующий) код:
// ❌ Плохо - приложение зависает!
void loadUser() {
final response = http.get('https://api.example.com/user'); // Ждет 2 секунды
print(response.body); // Только потом продолжает
// UI заморозилось на 2 секунды!
}
Асинхронный код с Future:
// ✅ Хорошо - UI остается отзывчивым!
Future<String> loadUser() async {
final response = await http.get('https://api.example.com/user');
return response.body; // Продолжить когда данные пришли
// UI не блокируется!
}
Что такое Future?
Future — это объект-обертка для асинхронного результата:
// Future может быть в одном из трех состояний:
Future<String> userFuture = fetchUser();
// 1. Pending (ожидание)
print(userFuture); // Instance of 'Future<String>'
// 2. Resolved (успешно выполнено)
Future<String> resolvedFuture = Future.value('John');
await resolvedFuture; // 'John'
// 3. Rejected (ошибка)
Future<String> rejectedFuture = Future.error('Network error');
// Выбросит исключение при await
Три состояния Future
Применимо на временной шкале:
0ms 1000ms 2000ms
├─ Pending ├─ выполняется ├─ Resolved или Rejected
│ │ │
│ │ └─> Завершено с 'John'
│ │ └─> Ошибка: 'Network error'
└────────────┴───────────────────┘
Code:
Future<String> user = fetchUser(); // Pending
await user; // Resolved/Rejected
Базовый пример
// Создание Future
Future<String> fetchUser() async {
await Future.delayed(Duration(seconds: 2));
return 'John Doe';
}
// Использование Future
void main() async {
print('Start'); // Выведется сразу
final user = await fetchUser();
print('User: $user'); // Выведется через 2 секунды
print('End'); // Выведется в конце
}
// Вывод:
// Start
// User: John Doe (через 2 сек)
// End
Работа с Future
1. await (ожидание)
Future<String> getName() async {
return 'John';
}
void main() async {
final name = await getName();
print('Name: $name'); // John
}
2. then() (цепочка)
fetchUser()
.then((user) {
print('User: $user');
return user.email;
})
.then((email) {
print('Email: $email');
})
.catchError((error) {
print('Error: $error');
});
3. catchError() (обработка ошибок)
try {
final result = await riskyOperation();
print('Success: $result');
} catch (e) {
print('Error: $e');
}
// Или
riskyOperation()
.then((result) => print('Success: $result'))
.catchError((error) => print('Error: $error'));
Future в Flutter UI
FutureBuilder — встроенный виджет для работы с Future:
class UserProfile extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<User>(
future: fetchUser(), // Future<User>
builder: (context, snapshot) {
// Три состояния:
if (snapshot.connectionState == ConnectionState.waiting) {
return CircularProgressIndicator(); // Загрузка
}
if (snapshot.hasError) {
return Text('Error: ${snapshot.error}'); // Ошибка
}
if (snapshot.hasData) {
final user = snapshot.data!;
return Column(
children: [
Text('Name: ${user.name}'),
Text('Email: ${user.email}'),
],
); // Успех
}
return SizedBox(); // Неожиданное состояние
},
);
}
}
Практические примеры
Пример 1: HTTP запрос
import 'package:http/http.dart' as http;
import 'dart:convert';
class User {
final String id;
final String name;
final String email;
User({
required this.id,
required this.name,
required this.email,
});
factory User.fromJson(Map<String, dynamic> json) {
return User(
id: json['id'],
name: json['name'],
email: json['email'],
);
}
}
// Future для HTTP запроса
Future<User> fetchUser(String userId) async {
try {
final response = await http.get(
Uri.parse('https://api.example.com/users/$userId'),
headers: {'Accept': 'application/json'},
).timeout(Duration(seconds: 10)); // Timeout
if (response.statusCode == 200) {
return User.fromJson(jsonDecode(response.body));
} else {
throw Exception('Failed to load user');
}
} on TimeoutException {
throw Exception('Request timeout');
} on SocketException {
throw Exception('No internet connection');
}
}
// Использование
class UserScreen extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<User>(
future: fetchUser('123'),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Scaffold(
appBar: AppBar(title: Text('Loading...')),
body: Center(child: CircularProgressIndicator()),
);
}
if (snapshot.hasError) {
return Scaffold(
appBar: AppBar(title: Text('Error')),
body: Center(child: Text('${snapshot.error}')),
);
}
final user = snapshot.data!;
return Scaffold(
appBar: AppBar(title: Text('User Profile')),
body: Center(
child: Column(
children: [
Text('ID: ${user.id}'),
Text('Name: ${user.name}'),
Text('Email: ${user.email}'),
],
),
),
);
},
);
}
}
Пример 2: Чтение файла
import 'dart:io';
Future<String> readFile(String filePath) async {
try {
final file = File(filePath);
return await file.readAsString();
} catch (e) {
throw Exception('Failed to read file: $e');
}
}
// Использование
void main() async {
try {
final content = await readFile('data.txt');
print('Content: $content');
} catch (e) {
print('Error: $e');
}
}
Пример 3: Future.delayed (имитация задержки)
// Для тестирования
Future<String> simulateNetworkCall() async {
await Future.delayed(Duration(seconds: 2));
return 'Data loaded';
}
// Использование
class LoadingWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
return FutureBuilder<String>(
future: simulateNetworkCall(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(child: CircularProgressIndicator());
}
return Center(child: Text(snapshot.data!));
},
);
}
}
Работа с несколькими Future
Future.wait() — ждем все Future
Future<void> loadMultipleData() async {
try {
final results = await Future.wait([
fetchUser('1'),
fetchPosts('1'),
fetchComments('1'),
]);
print('All loaded: $results');
} catch (e) {
print('Error: $e');
}
}
Future.any() — первый успешный Future
Future<String> fetchFromAnyServer() async {
return Future.any([
http.get('https://server1.com').timeout(Duration(seconds: 5)),
http.get('https://server2.com').timeout(Duration(seconds: 5)),
http.get('https://server3.com').timeout(Duration(seconds: 5)),
]);
}
Сравнение: Future vs Stream
Future | Stream
────────────────────────┼──────────────────────
Одно значение | Множество значений
Время выполнения | Несколько значений во времени
Примеры: | Примеры:
- HTTP запрос | - WebSocket
- Загрузка файла | - Sensor events
- Чтение из БД | - User input stream
- Простые async ops | - Real-time данные
Лучшие практики
1. Всегда обрабатывай ошибки
// ✅ Хорошо
try {
final result = await riskyOperation();
} catch (e) {
print('Error: $e');
}
// ❌ Плохо - может выбросить необработанное исключение
final result = await riskyOperation();
2. Используй FutureBuilder в UI
// ✅ Хорошо
FutureBuilder<Data>(
future: fetchData(),
builder: (context, snapshot) {
// Обработка всех состояний
},
)
// ❌ Плохо - может зависнуть
await fetchData(); // В build методе!
3. Используй timeout для сетевых запросов
// ✅ Хорошо
final response = await http.get(url).timeout(Duration(seconds: 10));
// ❌ Плохо - может висеть вечно
final response = await http.get(url);
Отличие async/await от then()
// Способ 1: async/await (рекомендуется)
Future<String> loadData() async {
try {
final result = await fetchData();
return 'Loaded: $result';
} catch (e) {
return 'Error: $e';
}
}
// Способ 2: then() (старый стиль)
Future<String> loadData() {
return fetchData()
.then((result) => 'Loaded: $result')
.catchError((e) => 'Error: $e');
}
// async/await более читаемый и приобретен!
Вывод
Future — это фундаментальный концепт асинхронного программирования в Dart:
✅ Не блокирует UI — приложение остается отзывчивым ✅ Простой синтаксис — async/await ✅ Обработка ошибок — try/catch ✅ Встроена в Flutter — FutureBuilder ✅ Основа для сетевых запросов — HTTP, WebSocket
Правило большого пальца:
- Долгоживущая операция → Future
- Несколько значений во времени → Stream
- В UI → FutureBuilder
- Несколько Future → Future.wait()
Без Future мобильные приложения были бы медленными и завислими. Future — это то, что делает Flutter приложения гладкими и отзывчивыми!