← Назад к вопросам

На каком потоке выполняются запросы в сеть?

2.2 Middle🔥 211 комментариев
#Асинхронность#Работа с сетью

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

На каком потоке выполняются сетевые запросы в Flutter

Это важный вопрос о работе многопоточности в мобильной разработке. Давайте разберёмся в деталях того, где и как Flutter выполняет сетевые операции.

Основной поток (Main/UI Thread) и фоновые потоки

В Flutter, как и в большинстве мобильных фреймворков, существует главный поток, отвечающий за обновление пользовательского интерфейса. Однако сетевые запросы выполняются на фоновых потоках, благодаря тому, что Dart использует асинхронное программирование с Future и async/await.

Основная идея: когда вы делаете сетевой запрос через HttpClient или пакет http, Dart автоматически переводит это на фоновый поток операционной системы. Это предотвращает блокировку UI потока.

Как это работает в Dart

Dart использует асинхронный runtime с поддержкой Event Loop. Это значит:

  1. Когда вы вызываете асинхронную операцию (Future), она не блокирует текущий поток
  2. Dart планирует выполнение на фоновом потоке
  3. Когда результат готов, событие помещается в очередь Event Loop
  4. Event Loop обрабатывает событие и обновляет UI на главном потоке
// Эта операция НЕ блокирует главный поток
final response = await http.get(
  Uri.parse('https://api.example.com/data'),
);

// Код выполняется асинхронно, UI остаётся отзывчивым

Использование Isolates для тяжёлых вычислений

Если сетевой ответ требует тяжёлой обработки, можно использовать Isolates (отдельные потоки Dart с собственной памятью):

// Тяжёлая обработка в отдельном isolate
final result = await compute(parseJson, responseBody);

// Где parseJson — функция, выполняющаяся в отдельном isolate
future<Map<String, dynamic>> parseJson(String jsonString) async {
  // Тяжёлые вычисления не заблокируют UI
  return json.decode(jsonString);
}

Практический пример: загрузка данных

class UserRepository {
  Future<User> fetchUser(int id) async {
    try {
      final response = await http.get(
        Uri.parse('https://api.example.com/users/$id'),
      );

      if (response.statusCode == 200) {
        // Это выполнится на главном потоке после получения результата
        return User.fromJson(jsonDecode(response.body));
      } else {
        throw Exception('Failed to load user');
      }
    } catch (e) {
      throw Exception('Network error: $e');
    }
  }
}

// В widget или provider
class UserNotifier extends StateNotifier<AsyncValue<User>> {
  Future<void> loadUser(int id) async {
    state = const AsyncValue.loading();
    state = await AsyncValue.guard(() => repository.fetchUser(id));
    // UI обновляется только когда данные готовы
  }
}

Важные детали

Event Loop в Dart: Главный поток в Dart имеет Event Loop, который обрабатывает:

  1. Микротаски (микро очередь)
  2. События (событийная очередь)

Сетевые запросы завершаются как события в событийной очереди.

Platform Channels для нативных операций: Если нужны специфичные для платформы операции (камера, геолокация), используются Platform Channels, которые также выполняют операции вне главного потока.

Решение о выборе подхода:

  • Обычные HTTP запросы → автоматически на фоновом потоке
  • Парсинг JSON из больших ответов → compute() для isolate
  • Операции с базой данных (sqlite) → обычно на фоновом потоке пакетом
  • Реально тяжёлые вычисления → создавайте свой isolate

Проблемы, которых нужно избежать

Неправильное использование await: не пишите await в обработчиках onClick, если это блокирует UI

Отсутствие error handling: всегда обрабатывайте исключения в Future

Memory leaks: отмены подписок на Stream при dispose widget'а

class MyWidget extends StatefulWidget {
  @override
  State<MyWidget> createState() => _MyWidgetState();
}

class _MyWidgetState extends State<MyWidget> {
  late Future<Data> future;

  @override
  void initState() {
    super.initState();
    future = repository.fetchData();
  }

  @override
  void dispose() {
    // Отменяем запросы если нужно
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return FutureBuilder<Data>(
      future: future,
      builder: (context, snapshot) {
        if (snapshot.connectionState == ConnectionState.waiting) {
          return const CircularProgressIndicator();
        } else if (snapshot.hasError) {
          return Text('Error: ${snapshot.error}');
        } else {
          return Text(snapshot.data?.title ?? '');
        }
      },
    );
  }
}

Выводы

Сетевые запросы в Flutter выполняются на фоновых потоках благодаря асинхронной архитектуре Dart. Главный поток всегда остаётся свободным для обновления UI. Для оптимизации используйте compute() при необходимости обработки больших объёмов данных.