Section 2/161 menit

2. Masalah yang Dipecahkan

2. Masalah yang Dipecahkan

Kombinasi Multiple Async Sources yang Verbose

Menggabungkan dua stream async tanpa library membutuhkan code yang kompleks dan rawan error.

swift
// ❌ TANPA Async Algorithms: merge dua stream manual — verbose dan rawan race
func processEvents() async {
    // Tidak ada cara idiomatis untuk merge dua AsyncStream
    // Harus gunakan TaskGroup dengan coordination yang kompleks
    await withTaskGroup(of: AppEvent.self) { group in
        group.addTask {
            for await event in networkEventStream() {
                return event
            }
            fatalError("stream ended unexpectedly")
        }
        group.addTask {
            for await event in userActionStream() {
                return event
            }
            fatalError("stream ended unexpectedly")
        }

        // Ini hanya mengambil SATU event, bukan semua event dari kedua stream
        // Merge yang benar membutuhkan implementasi koordinasi sendiri
        for await event in group {
            handleEvent(event)
        }
    }
}
swift
// ✓ DENGAN Async Algorithms: merge idiomatis dalam satu baris
import AsyncAlgorithms

func processEvents() async {
    let merged = merge(networkEventStream(), userActionStream())
    for await event in merged {
        handleEvent(event)
    }
}

Debounce Input Pengguna tanpa Timer Manual

Membatasi laju pemrosesan input (seperti search field) membutuhkan DispatchWorkItem dan management timer yang rumit.

swift
// ❌ TANPA Async Algorithms: debounce dengan Timer manual
class SearchViewModel {
    private var debounceWorkItem: DispatchWorkItem?

    func onSearchTextChanged(_ text: String) {
        debounceWorkItem?.cancel()
        debounceWorkItem = DispatchWorkItem { [weak self] in
            Task { await self?.performSearch(query: text) }
        }
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3, execute: debounceWorkItem!)
        // Problem: tidak thread-safe, memory management manual, cancel bisa race
    }
}
swift
// ✓ DENGAN Async Algorithms: debounce type-safe, cancellation otomatis
@MainActor
class SearchViewModel: ObservableObject {
    @Published var results: [SearchResult] = []

    private let searchInput = AsyncChannel<String>()

    init() {
        Task {
            let debounced = searchInput.debounce(for: .milliseconds(300))
            for await query in debounced {
                results = try await performSearch(query: query)
            }
        }
    }

    func onSearchTextChanged(_ text: String) async {
        await searchInput.send(text)
    }
}

Batching Event untuk Efisiensi Network

Mengumpulkan event yang datang cepat dan memproses dalam batch memerlukan buffer manual.

swift
// ❌ TANPA Async Algorithms: batch manual dengan timer dan array buffer
actor EventBatcher {
    private var buffer: [AnalyticsEvent] = []
    private var flushTimer: Timer?

    func append(_ event: AnalyticsEvent) {
        buffer.append(event)
        if buffer.count >= 50 {
            flush()
        } else if flushTimer == nil {
            flushTimer = Timer.scheduledTimer(withTimeInterval: 5.0, repeats: false) { _ in
                Task { await self.flush() }
            }
        }
    }

    private func flush() {
        guard !buffer.isEmpty else { return }
        let batch = buffer
        buffer.removeAll()
        flushTimer?.invalidate()
        flushTimer = nil
        Task { try await uploadBatch(batch) }
    }
}
swift
// ✓ DENGAN Async Algorithms: chunked(by:) handles batching secara deklaratif
func startEventProcessor(stream: AsyncStream<AnalyticsEvent>) async throws {
    let batched = stream.chunked(by: .repeating(every: .seconds(5)))
    // Atau batch berdasarkan count DAN waktu:
    let batched2 = stream.chunks(ofCount: 50)

    for await batch in batched {
        try await uploadBatch(Array(batch))
    }
}