Задачи создавать научились, поняли основную разницу между Task и Task.detached. Но что будет лежать внутри этих задач? Как этим управлять и как с этим работать?
Одно из назначений задач - это организация работы асинхронных функций. Функция помеченная ключевым словом async не вернёт результат сразу же. Она его вернёт через некоторое время. Именно поэтому данную функцию нельзя просто вызвать из синхронного кода. Такие функции могут вызываться либо в таких же асинхронных функциях, либо в Task.
func fetchUserFromDatabase() async throws -> User {
.....
}
async - означает, что функция должна быть вызвана из асинхронного контекста.
throws - означает, что функция может выкинуть исключение
Task {
do {
let user = try await fetchUserFromDatabase()
let userAvatar = try await getAvatar(userId: user.userId)
/// Последовательное исполнение задач, сначала загрузится пользователь,
/// затем начнётся подгрузка аватара пользователя
} catch {
/// Обработка ошибок
}
}
В примере выше мы уже использовали ключевое слово await. Вы скорее всего догадываетесь, что await нужен для того чтобы дождаться результата выполнения асинхронной функции. Но что именно происходит в момент вызова await?
await - это место, в котором останавливается выполнение кода функции - Suspention point. Остановка происходит до тех пор пока написанная после await функция не вернёт какое-нибудь значение. Что происходит с потоком на котором выполнялась функция? Если код приостанавливается и ждёт выполнения функции, то где он ждёт?
ОЧЕНЬ ВАЖНО
На самом деле, когда мы пишем Await происходит следующее:
Из выше описанных пунктов следует, что после того как мы вернёмся в остановленную функцию с результатом выполнения, то поток будет отличаться от потока с которого начиналось выполнение.
Task {
/// Здесь мы были например на Thread 5
let user = try await fetchUserFromDatabase()
/// Здесь мы уже будет на другом потоке (иногда можем попасть и на тот же самый)
}