Published on

Swiftda async/await asoslari

Authors

Swift Concurrency — Swift 5.5 (iOS 15+) da kiritilgan, asinxron kodni sinxron kodday oson yozish imkonini beruvchi tizim. Ilgari tarmoq so'rovlari, fayllarni o'qish yoki ma'lumotlar bazasi bilan ishlash uchun callback (closure) ishlatilgan — bu kod o'qib bo'lmaydigan darajada murakkablashib ketardi. async/await buni tubdan hal qiladi — asinxron kodni xuddi oddiy sinxron koddek yozish mumkin.

Concurrency nima? — Bu bir nechta ishni "bir vaqtda" bajarish tushunchasi. Masalan, ilova serverdan ma'lumot yuklab olayotgan paytda foydalanuvchi UI bilan ishlashni davom ettirishi kerak. Agar hammasi sinxron bo'lsa — ekran muzlab qoladi.

Sinxron vs Asinxron

Sinxron kod — har bir qator oldingi qator tugaguncha kutadi. Agar biror amal 3 soniya vaqt olsa, dastur 3 soniya to'xtab qoladi va UI muzlaydi. Asinxron kod esa kutish paytida boshqa ishlarni davom ettiradi — foydalanuvchi hech narsani sezmaydi.

async kalit so'zi funksiyaga qo'yiladi — "bu funksiya vaqt olishi mumkin" degan ma'noni beradi. await esa shu funksiya natijasini kutishni bildiradi, lekin bu paytda tizim boshqa ishlarni bajaradi.

// ═══════════════════════════════════════
//  SINXRON — har qator navbatida, kutadi
// ═══════════════════════════════════════
func sinxronYuklash() {
    print("1. Boshlanmoqda")
    // Bu joy 3 soniya kutadi — HAMMASI to'xtaydi
    Thread.sleep(forTimeInterval: 3)
    print("2. Yuklandi")        // 3 soniyadan keyin
    print("3. UI yangilandi")   // 3 soniyadan keyin
    // Muammo: UI 3 soniya muzlaydi!
}


// ═══════════════════════════════════════
//  ASINXRON — kutish paytida boshqa ishlar davom etadi
// ═══════════════════════════════════════
func asinxronYuklash() async {
    print("1. Boshlanmoqda")
    // await — natijani kutadi, lekin tizim boshqa ishlarni davom etadi
    try? await Task.sleep(for: .seconds(3))
    print("2. Yuklandi")        // 3 soniyadan keyin
    print("3. UI yangilandi")   // 3 soniyadan keyin
    // UI muzlamaydi — boshqa ishlar bajariladi
}

async funksiya yaratish

Async funksiya yaratish uchun funksiya imzosiga async kalit so'zini qo'shish kifoya. Agar funksiya xato ham tashlashi mumkin bo'lsa, async throws yoziladi. Async funksiyani chaqirish uchun ikki yo'l mavjud: boshqa async funksiya ichidan await bilan yoki sinxron joydan Task { } bloki ichidan.

// ═══════════════════════════════════════
//  ODDIY ASYNC FUNKSIYA
// ═══════════════════════════════════════
// async — bu funksiya vaqt olishi mumkin degan ma'no
func foydalanuvchiniYukla(id: Int) async -> String {
    // Tarmoq so'rovi simulyatsiyasi
    try? await Task.sleep(for: .seconds(1))
    return "Foydalanuvchi #\(id)"
}

// async throws — xato ham tashlashi mumkin
func ma'lumotYukla(url: String) async throws -> Data {
    guard let url = URL(string: url) else {
        throw URLError(.badURL)
    }
    // URLSession.shared.data — async funksiya
    let (data, _) = try await URLSession.shared.data(from: url)
    return data
}


// ═══════════════════════════════════════
//  ASYNC FUNKSIYANI CHAQIRISH
// ═══════════════════════════════════════
// async funksiyani faqat async kontekstdan chaqirish mumkin

// 1-usul: boshqa async funksiya ichidan
func asosiyFunksiya() async {
    let ism = await foydalanuvchiniYukla(id: 1)
    print(ism)  // "Foydalanuvchi #1"
}

// 2-usul: Task bloki ichidan (sinxron kontekstdan)
func sinxronJoy() {
    Task {
        let ism = await foydalanuvchiniYukla(id: 1)
        print(ism)
    }
    // Bu yerda davom etadi — kutmaydi
    print("Task yaratildi")
}

Ketma-ket va parallel bajarish

Oddiy await bilan chaqirilgan funksiyalar ketma-ket ishlaydi — biri tugaguncha keyingisi boshlanmaydi. Lekin ko'p hollarda bir-biriga bog'liq bo'lmagan so'rovlarni parallel bajarish ancha tezroq. Buning uchun async let konstruktsiyasi ishlatiladi — u asinxron vazifani darhol boshlaydi, natijani esa keyinroq await bilan olish mumkin.

// ═══════════════════════════════════════
//  KETMA-KET — biri tugaguncha ikkinchisi boshlanmaydi
// ═══════════════════════════════════════
func ketmaKet() async {
    let foydalanuvchi = await foydalanuvchiniYukla(id: 1)    // 1 soniya
    let profil = await profilniYukla(id: 1)                   // 1 soniya
    let postlar = await postlarniYukla(userId: 1)             // 1 soniya
    // Jami: 3 soniya (ketma-ket)
}


// ═══════════════════════════════════════
//  PARALLEL — async let bilan bir vaqtda
// ═══════════════════════════════════════
func parallel() async {
    // async let — hoziroq boshlash, keyinroq natijani olish
    async let foydalanuvchi = foydalanuvchiniYukla(id: 1)     // boshlandi
    async let profil = profilniYukla(id: 1)                    // boshlandi
    async let postlar = postlarniYukla(userId: 1)              // boshlandi

    // Uchala so'rov BIR VAQTDA ishlaydi
    // await — natijalarni kutish
    let f = await foydalanuvchi
    let p = await profil
    let po = await postlar
    // Jami: ~1 soniya (parallel — eng uzuni qadar)
}

func profilniYukla(id: Int) async -> String {
    try? await Task.sleep(for: .seconds(1))
    return "Profil #\(id)"
}

func postlarniYukla(userId: Int) async -> [String] {
    try? await Task.sleep(for: .seconds(1))
    return ["Post 1", "Post 2"]
}

Callback dan async/await ga o'tish

Ilgari iOS dasturlashda asinxron ish uchun completion handler (callback) ishlatilgan. Bir nechta ketma-ket asinxron so'rov kerak bo'lganda, callback ichida callback, uning ichida yana callback yozish kerak edi — bu "Callback Hell" deb ataladi. async/await bilan xuddi shu mantiq tekis, sodda va o'qish oson kodga aylanadi.

// ═══════════════════════════════════════
//  ESKI USUL — Callback Hell
// ═══════════════════════════════════════
func eskiUsul() {
    yukla(url: "users/1") { user in
        yukla(url: "profiles/\(user.id)") { profile in
            yukla(url: "posts?user=\(user.id)") { posts in
                // 3 qavatli callback — o'qish qiyin!
                print(user, profile, posts)
            }
        }
    }
}


// ═══════════════════════════════════════
//  YANGI USUL — async/await
// ═══════════════════════════════════════
func yangiUsul() async throws {
    let user = try await yukla(url: "users/1")
    let profile = try await yukla(url: "profiles/\(user.id)")
    let posts = try await yukla(url: "posts?user=\(user.id)")
    // Tekis, o'qish oson, xatolarni try/catch bilan ushlash
    print(user, profile, posts)
}

do-try-catch bilan xatolarni ushlash

Asinxron funksiya xato tashlashi mumkin bo'lganda, try await yoziladi — try xatoni ushlash uchun, await natijani kutish uchun. do-catch bloki ichida turli xato turlarini alohida ushlash mumkin — masalan, internet yo'qligi va boshqa xatolarni ajratib ko'rsatish.

func xavfsizYuklash() async {
    do {
        // try await — xato bo'lishi mumkin bo'lgan asinxron chaqiruv
        let data = try await ma'lumotYukla(url: "https://api.example.com/data")
        print("Yuklandi: \(data.count) bayt")
    } catch URLError.notConnectedToInternet {
        print("Internet yo'q!")
    } catch {
        print("Xato: \(error.localizedDescription)")
    }
}

🎯 Topshiriq

3 ta async funksiya yarating: ismYukla(), yoshYukla(), emailYukla() — har biri 1 soniya kutib String/Int qaytarsin. Avval ketma-ket chaqiring va vaqtni o'lchang. Keyin async let bilan parallel chaqiring. Farqni kuzating.

Buy mea coffee