Giới thiệu về Async và Await trong Swift
Trong phiên bản Swift 5.5, Apple đã giới thiệu một mô hình lập trình đồng thời mới, đánh dấu bước ngoặt quan trọng trong việc phát triển ứng dụng. Hai từ khóa async và await được thiết kế đặc biệt giúp lập trình viên có thể xử lý mã bất đồng bộ một cách đơn giản và an toàn hơn.
Trước khi có async/await, lập trình viên thường phải vật lộn với các phương pháp như callbacks, completion handlers, hay closures, dẫn đến mã lộn xộn và khó đọc, đặc biệt trong các tình huống phức tạp (nỗi đau gọi là callback hell). Với async/await, việc viết code bất đồng bộ trở nên mạch lạc và dễ theo dõi hơn.
Khái niệm về Async và Await
-
Async: Khi một hàm được đánh dấu là async, điều này có nghĩa là hàm này có khả năng thực hiện một tác vụ mà có thể sẽ mất thời gian (ví dụ: gọi API hoặc xử lý dữ liệu lớn) mà không làm chặn luồng chính (main thread). Điều này cho phép ứng dụng tiếp tục hoạt động mượt mà trong khi chờ tác vụ hoàn tất.
-
Await: Từ khóa await cho phép chúng ta đợi kết quả từ hàm bất đồng bộ. Khi được sử dụng, luồng thực thi sẽ tạm dừng tại điểm đó cho đến khi hàm hoàn thành. Điều này giúp mã trở nên tuyến tính và dễ tiếp cận hơn.
Ưu điểm của Async/Await so với Callback
- Tính tuyến tính: Giúp mã dễ đọc hơn, gần giống như mã đồng bộ.
- Quản lý lỗi tốt hơn: Việc sử dụng từ khóa
try/catch
giúp bạn dễ dàng xử lý lỗi một cách có cấu trúc.
Ví dụ cơ bản về Async/Await
Dưới đây là ví dụ đơn giản về cách sử dụng mô hình lập trình đồng thời của Swift với từ khóa async và await để tải dữ liệu từ một URL.
swift
import Foundation
func fetchData(from url: String) async throws -> Data {
guard let url = URL(string: url) else {
throw URLError(.badURL)
}
let (data, _) = try await URLSession.shared.data(from: url)
return data
}
Task {
do {
let data = try await fetchData(from: "https://example.com")
print("Dữ liệu đã được lấy: \(data)")
} catch {
print("Không thể lấy dữ liệu: \(error)")
}
}
Cách hoạt động
- Từ khóa async cho phép hàm thực hiện tác vụ mà không làm chặn luồng chính.
- Từ khóa await tạm dừng thực thi cho đến khi việc tải dữ liệu hoàn tất.
- Tạo một
Task
block cho phép gọi các hàm bất đồng bộ từ bất kỳ đâu trong ứng dụng. - Kết hợp
try
vàawait
để gọi hàmfetchData
và bắt lỗi nếu có.
Sử dụng Async Let để Tải Dữ Liệu Đồng Thời
Bạn có thể sử dụng từ khóa async let
để khởi tạo và chạy nhiều tác vụ cùng lúc, rồi chờ tất cả hoàn thành.
swift
import Foundation
func fetchMultipleData() async {
async let data1 = fetchData(from: "https://example.com/1")
async let data2 = fetchData(from: "https://example.com/2")
async let data3 = fetchData(from: "https://example.com/3")
do {
let results = try await (data1, data2, data3)
print("Dữ liệu đã được lấy: \(results)")
} catch {
print("Có lỗi trong quá trình lấy dữ liệu: \(error)")
}
}
Task {
await fetchMultipleData()
}
Xử lý Thời Gian Chờ và Hủy Bỏ Tác Vụ
Để đảm bảo rằng một tác vụ không chạy vô hạn, bạn có thể thêm khả năng hủy bỏ và xử lý timeout trong mã.
swift
import Foundation
func fetchDataWithTimeout(from url: String) async throws -> Data {
let task = Task {
try await fetchData(from: url)
}
let timeoutTask = Task {
try await Task.sleep(nanoseconds: 5_000_000_000)
task.cancel()
}
do {
return try await task.value
} catch {
timeoutTask.cancel()
throw error
}
}
Task {
do {
let data = try await fetchDataWithTimeout(from: "https://example.com")
print("Dữ liệu đã được lấy: \(data)")
} catch {
print("Tác vụ đã bị hủy hoặc quá thời gian: \(error)")
}
}
Sử dụng Task Groups để Quản lý Nhiều Tác Vụ
Quản lý nhiều tác vụ với withThrowingTaskGroup
swift
import Foundation
func fetchMultipleDataWithGroup(urls: [String]) async throws -> [Data] {
return try await withThrowingTaskGroup(of: Data.self) { group in
for url in urls {
group.addTask {
try await fetchData(from: url)
}
}
var results: [Data] = []
for try await result in group {
results.append(result)
}
return results
}
}
Task {
do {
let data = try await fetchMultipleDataWithGroup(urls: ["https://example.com/1", "https://example.com/2", "https://example.com/3"])
print("Dữ liệu đã được lấy: \(data)")
} catch {
print("Có lỗi khi lấy dữ liệu: \(error)")
}
}
Kiểm Tra Kết Nối Internet
Trước khi thực hiện bất kỳ yêu cầu mạng nào, hãy kiểm tra sự kết nối Internet.
swift
import Foundation
import SystemConfiguration
class Reachability {
static func isConnectedToNetwork() -> Bool {
// Logic kiểm tra kết nối ở đây
}
}
func fetchDataIfConnected(from url: String) async throws -> Data {
guard Reachability.isConnectedToNetwork() else {
throw URLError(.notConnectedToInternet)
}
return try await fetchData(from: url)
}
Task {
do {
let data = try await fetchDataIfConnected(from: "https://example.com")
print("Dữ liệu đã được lấy: \(data)")
} catch {
print("Không thể lấy dữ liệu: \(error)")
}
}
Tổng kết
Async và Await trong Swift là những công cụ mạnh mẽ giúp viết mã bất đồng bộ dễ dàng hơn, gọn gàng và hiệu quả hơn. Cho dù bạn đang xử lý các tác vụ đơn giản hay phức tạp, phương pháp này mang lại sự linh hoạt và an toàn cho việc quản lý các tác vụ đồng thời. Bắt đầu khám phá ngay hôm nay và nâng cao kỹ năng lập trình bất đồng bộ của bạn lên một tầng cao mới!
source: viblo