Что такое асинхронность в Dart?

Ответ

Асинхронность в Dart — это модель выполнения, при которой долгие операции (сетевые запросы, чтение файлов, вычисления) не блокируют основной поток (изолят), отвечающий за отрисовку UI и обработку событий. Это критически важно для поддержания плавности интерфейса во Flutter.

Основные концепции:

  1. Future<T> — объект-обещание, который представляет результат (успешный T или ошибка) некоторой асинхронной операции, которая завершится в будущем.
  2. async / await — ключевые слова, которые позволяют писать асинхронный код в синхронном, линейном стиле, что гораздо читабельнее цепочек .then().
  3. Stream<T> — последовательность асинхронных событий, поступающих со временем (например, события от сервера через WebSocket, пользовательский ввод).

Практический пример (сетевой запрос):

import 'package:http/http.dart' as http;

Future<void> fetchUserData(String userId) async {
  // `await` приостанавливает выполнение этой функции, но НЕ основного потока.
  // Пока мы ждем ответа от сервера, UI может обрабатывать другие события.
  try {
    final response = await http.get(
      Uri.parse('https://api.example.com/users/$userId'),
    );

    if (response.statusCode == 200) {
      // Данные получены, можно обновить состояние виджета
      print('User data: ${response.body}');
    } else {
      throw Exception('Failed to load user. Status: ${response.statusCode}');
    }
  } on SocketException catch (e) {
    // Обработка ошибок сети
    print('Network error: $e');
  } catch (e) {
    // Обработка любых других ошибок
    print('Unexpected error: $e');
  }
}

// Использование:
// В методе initState() виджета или по нажатию кнопки:
// await fetchUserData('123');

Ключевые моменты:

  • Функция, содержащая await, должна быть помечена как async.
  • await не блокирует весь изолят, он лишь приостанавливает выполнение текущей асинхронной функции.
  • Ошибки в асинхронных операциях отлично ловятся стандартными блоками try/catch.
  • Для работы с множеством параллельных операций используют Future.wait().

Без асинхронности любая долгая операция "замораживала" бы интерфейс приложения.

Ответ 18+ 🔞

Давай разберём эту асинхронность в Dart, чтобы было понятно, как не угробить интерфейс своего приложения. Это, блядь, основа основ, без неё твой UI будет тормозить так, что пользователь успеет сходить за кофе, вернуться и ещё тебя обматерить.

Суть в чём: Вот представь, твоё приложение — это бармен в забитой хате. Основной поток (изолят) — это он сам. Если он пойдёт в подвал на десять минут за бухлом, пока клиент ждёт свой стакан, народ взвоет. Так вот асинхронность — это когда бармен кричит подсобнику: «Вась, сбегай за ящиком!», а сам продолжает наливать другим. Подсобник — это твой Future. Он обещает (Future — буквально «будущее»), что притащит ящик. Бармен не стоит тупо, уставившись в дверь в подвал, он работает. Вот и твой UI не должен тупить, пока что-то грузится из сети.

Ключевые штуки:

  1. Future<T> — это, ёпта, обещание. Не результат, а именно обещание, что результат (или ошибка, пидарас шерстяной) будет. Потом. Не сейчас.
  2. async / await — просто магия, чтобы не писать эти цепочки из .then(), от которых глаза вытекают. Пишешь код почти как обычный, линейный.
  3. Stream<T> — это когда события прут не разово, а потоком. Как уведомления из чата или курс акций. Постоянная течь, которую надо грамотно подтирать.

Смотри, как на практике выглядит (запрос в сеть):

import 'package:http/http.dart' as http;

Future<void> fetchUserData(String userId) async {
  // Ключевой момент! `await` тут НЕ вешает весь движок приложения.
  // Он говорит: «Э, функция, стопэ. Жди тут ответа от сервера.
  // А я, главный поток, пойду анимации крутить и кнопки обрабатывать».
  try {
    final response = await http.get(
      Uri.parse('https://api.example.com/users/$userId'),
    );

    if (response.statusCode == 200) {
      // Ура, данные пришли. Теперь можно, например, `setState()` вызвать.
      print('User data: ${response.body}');
    } else {
      // Сервер ответил, но хернёй какой-то. Кидаем исключение.
      throw Exception('Failed to load user. Status: ${response.statusCode}');
    }
  } on SocketException catch (e) {
    // Ловим конкретно ошибки сети. Интернет вырубили, роутер сгорел.
    print('Network error: $e');
  } catch (e) {
    // А тут ловится всё остальное, что пошло не так. На всякий пожарный.
    print('Unexpected error: $e');
  }
}

// Как юзать:
// Где-нибудь в `initState()` или по клику на кнопку:
// await fetchUserData('123');

Важные фишки на заметку:

  • Функция, где есть await, обязательно должна быть async. Это как договорённость.
  • await — это не блокировка всего нахуй, это вежливая пауза для конкретной функции. Весь остальной мир живёт своей жизнью.
  • Ошибки ловятся обычным try/catch — красота.
  • Если нужно запустить кучу операций параллельно и ждать все сразу — есть Future.wait(). Штука мощная.

Если коротко: без этой асинхронности любая операция, которая длится дольше 16 миллисекунд, сделает твой интерфейс дерганым куском дерьма. А с ней — всё летает, пользователь доволен, и ты не выглядишь ебанько, который не умеет в современную разработку.

Видео-ответы