Async/Await คือคู่ของคำสำคัญสำหรับการเขียนโค้ดแบบไม่ตรงกันในสไตล์ที่ตรงกัน พร้อมใช้งานใน Swift ตั้งแต่ iOS 13 และใน Kotlin ด้วยโคโรทีน ตาม Apple Swift Documentation, 2026, Async/Await แทนที่ chain ของ callback และ GCD ทำให้โค้ดแบบไม่ตรงกันเป็นเชิงเส้นและอ่านง่าย คำสำคัญ async ทำเครื่องหมายฟังก์ชันว่าไม่ตรงกัน และ await หยุดการทำงานชั่วคราวจนกว่าจะได้รับผลลัพธ์
ประเด็นสำคัญ
Async/Await คือโครงสร้างภาษาที่ช่วยให้คุณเขียนโค้ดแบบไม่ตรงกันได้เป็นเชิงเส้นเท่ากับโค้ดแบบตรงกัน ใน Swift มันปรากฏใน iOS 13 / macOS 10.15 พร้อมกับเฟรมเวิร์ก Swift Concurrency ใน Kotlin async/await พร้อมใช้งานผ่านไลบรารีโคโรทีน (kotlinx.coroutines) ตั้งแต่เวอร์ชัน 1.3
ก่อน async/await โค้ดแบบไม่ตรงกันถูกสร้างขึ้นบน callback, GCD หรือ RxSwift สายโซ่ของ callback ที่ซ้อนกันนำไปสู่ นรกของ callback — การซ้อนกันลึกที่ทำให้การอ่านและการดีบักซับซ้อน Async/Await แก้ปัญหานี้โดยอนุญาตให้ฟังก์ชันแบบไม่ตรงกัน “หยุดชั่วคราว” ที่จุด await และเริ่มใหม่หลังจากได้รับผลลัพธ์
ตามข้อมูลของ Google (2025) การใช้ async/await ใน Kotlin ลดจำนวนบรรทัดของโค้ดแบบไม่ตรงกันลง 40–60% เมื่อเทียบกับแนวทางแบบ callback ใน Swift การนำ Swift Concurrency มาใช้ถึง 68% ในหมู่แอปพลิเคชันที่เผยแพร่ในปี 2025 iOS 16 เพิ่มการสนับสนุน Swift Concurrency ใน UIKit, SwiftUI และ Foundation ทำให้ async/await เป็นเครื่องมือมาตรฐานสำหรับโปรเจกต์ Apple ใหม่ทั้งหมด
ความแตกต่างหลักระหว่าง async/await และเธรดคือ การหยุดชั่วคราวโดยไม่บล็อก เมื่อฟังก์ชันพบ await มันจะหยุดชั่วคราว ปล่อยเธรดปัจจุบันสำหรับงานอื่น ๆ หลังจากการดำเนินการแบบไม่ตรงกันเสร็จสมบูรณ์ ฟังก์ชันจะเริ่มใหม่บนเธรดเดียวกันหรือเธรดอื่น สิ่งนี้เรียกว่าการทำงานหลายอย่างร่วมกัน
ฟังก์ชัน async ถูกคอมไพล์เป็นเครื่องสถานะ — ออโตมาตันจำกัดที่จัดการสถานะการทำงาน ที่จุด await คอมไพเลอร์บันทึกบริบท (ตัวแปรท้องถิ่น ที่อยู่ส่งคืน) และส่งมอบการควบคุมให้รันไทม์ เมื่อผลลัพธ์พร้อม รันไทม์จะกู้คืนบริบทและดำเนินการต่อ
ใน Swift เครื่องสถานะนี้ถูกใช้งานที่ระดับคอมไพเลอร์ SIL (Swift Intermediate Language) ใน Kotlin ใช้กลไก Continuation Passing Style (CPS): ฟังก์ชัน suspend แต่ละตัวรับพารามิเตอร์ Continuation ที่ซ่อนอยู่ซึ่งผลลัพธ์จะถูกส่งกลับผ่านพารามิเตอร์นี้ ทั้งสองแนวทางรับประกันการเริ่มใหม่ที่ปลอดภัยโดยไม่มีการรั่วไหลของหน่วยความจำ
แนวทาง callback ต้องการส่ง closure ที่ถูกเรียกหลังจากการดำเนินการเสร็จสมบูรณ์ ด้วยคำขอตามลำดับสามรายการ คุณจะได้การซ้อนกันสามระดับพร้อมการจัดการข้อผิดพลาดในแต่ละระดับ Async/Await เปลี่ยนคำขอสามรายการเดียวกันเป็นสามบรรทัดตามลำดับด้วยบล็อก catch เดียว
GCD (DispatchQueue) แก้ปัญหานรกของ callback ผ่านคิวแบบอนุกรมและ DispatchGroup แต่ยังคง冗長 สำหรับงานง่าย ๆ — โหลดผู้ใช้ จากนั้นเพื่อน จากนั้น UI — จำเป็นต้องสร้างคิว กลุ่ม และบล็อกแจ้งเตือน Async/Await ทำงานเดียวกันด้วยสามบรรทัดในฟังก์ชันเดียว
| ด้าน | Callback | GCD | Async/Await |
|---|---|---|---|
| การซ้อนกัน | ลึก (พีระมิดแห่งความหายนะ) | ปานกลาง (กลุ่ม+แจ้งเตือน) | เชิงเส้น (ราบ) |
| การจัดการข้อผิดพลาด | ต่อ callback | ด้วยตนเอง | รวมศูนย์ (try/catch) |
| การยกเลิก | ด้วยตนเอง | จำกัด | Task.cancel() |
| ความปลอดภัยของเธรด | ด้วยตนเอง | ผ่านคิวอนุกรม | ผ่าน MainActor |
ตาม Apple WWDC 2024 Swift Concurrency async/await เป็นแนวทางที่แนะนำสำหรับโค้ดใหม่ GCD ยังคงใช้สำหรับการรวมกับไลบรารี C และสถานการณ์การจัดการเธรดระดับต่ำเฉพาะ
Task คือหน่วยพื้นฐานของงานแบบไม่ตรงกันใน Swift Task ถูกสร้างขึ้นในบริบทของ Actor ที่มีอยู่หรือบนเธรดใดก็ได้ ภายใน Task สามารถเรียกฟังก์ชัน async ผ่าน await ได้ TaskGroup อนุญาตให้เริ่มงานย่อยหลายงานพร้อมกันและรวบรวมผลลัพธ์ — เป็นเวอร์ชันปรับปรุงของ DispatchGroup
Actor คือประเภทอ้างอิงที่ปลอดภัยต่อเธรดซึ่งป้องกันสถานะจากการแข่งข้อมูล คอมไพเลอร์รับประกันว่าการเข้าถึงคุณสมบัติของ Actor ทำได้ผ่านการเรียก async หรือภายใน isolation ของ Actor เท่านั้น Actor แทนที่ DispatchQueue แบบอนุกรมเพื่อปกป้องสถานะที่เปลี่ยนแปลงร่วมกันได้โดยไม่ต้องล็อกด้วยตนเอง
หลักการของ Structured Concurrency กล่าวว่า: งานแบบไม่ตรงกันทุกงานมีผู้ปกครอง และผู้ปกครองจะไม่เสร็จสมบูรณ์จนกว่างานย่อยทั้งหมดจะเสร็จสมบูรณ์ หากงาน A เริ่ม Task { await B() } แล้ว A จะรอ B สิ่งนี้ป้องกันการรั่วไหลของงานและรับประกันวงจรชีวิตที่คาดเดาได้
ใน Kotlin async/await ถูกใช้งานผ่าน โคโรทีน — เธรดน้ำหนักเบาของภาษา ฟังก์ชันถูกทำเครื่องหมายด้วยคำสำคัญ suspend (คล้ายกับ async ของ Swift) สำหรับการเริ่มใช้ launch (ยิงแล้วลืม) หรือ async (พร้อมผลลัพธ์) Await ถูกเรียกเพื่อรับผลลัพธ์จาก async
Dispatcher กำหนดว่าโคโรทีนทำงานบนพูลเธรดใด: Dispatchers.Main สำหรับ UI, Dispatchers.IO สำหรับเครือข่าย/ดิสก์ และ Dispatchers.Default สำหรับงานที่ใช้ CPU มาก Structured Concurrency รับประกันผ่าน CoroutineScope — เมื่อขอบเขตถูกยกเลิก โคโรทีนย่อยทั้งหมดจะถูกยกเลิก
ตาม JetBrains (2025) 97% ของแอป Android ใน Google Play ใช้ kotlinx.coroutines และ 82% ของแอปเหล่านั้นใช้ async/await สำหรับคำขอเครือข่าย โคโรทีนกลายเป็นมาตรฐานโดยพฤตินัยสำหรับการเขียนโปรแกรมแบบไม่ตรงกันใน Android Kotlin Multiplatform ยังสนับสนุนโคโรทีน ทำให้สามารถใช้โค้ดแบบไม่ตรงกันร่วมกันบน Android, iOS และฝั่งเซิร์ฟเวอร์
มาดูสองตัวอย่างสำหรับแต่ละภาษา: การโหลดข้อมูลตามลำดับและคำขอแบบขนานด้วย TaskGroup หรือ async/await
await หยุดการทำงานชั่วคราวจนกว่าจะได้รับข้อมูลผู้ใช้ จากนั้นจนกว่าจะได้รับเพื่อน ไม่มี closure ซ้อนกัน
func loadProfile() async throws -> Profile {
let user = try await api.fetchUser()
let friends = try await api.fetchFriends(for: user.id)
return Profile(user: user, friends: friends)
}
TaskGroup เริ่มงานแบบขนานและรวบรวมผลลัพธ์ในอาร์เรย์ ลำดับของผลลัพธ์อาจไม่ตรงกับลำดับการเริ่ม
func loadParallel() async throws -> [String] {
await withThrowingTaskGroup(of: String.self) { group in
group.addTask { try await api.fetchName() }
group.addTask { try await api.fetchEmail() }
group.addTask { try await api.fetchAvatar() }
var results = [String]()
for try await value in group { results.append(value) }
return results
}
}
ฟังก์ชัน suspend สามารถเรียกฟังก์ชัน suspend อื่น ๆ ได้ คล้ายกับ Swift: การเรียกตามลำดับ
suspend fun loadProfile(): Profile {
val user = api.fetchUser()
val friends = api.fetchFriends(user.id)
return Profile(user, friends)
}
ใน Kotlin ความขนานทำได้ผ่าน coroutineScope ด้วย async สำหรับแต่ละคำขอ
suspend fun loadParallel(): List<String> = coroutineScope {
val name = async { api.fetchName() }
val email = async { api.fetchEmail() }
val avatar = async { api.fetchAvatar() }
listOf(name.await(), email.await(), avatar.await())
}
Task { } ที่ถูกลืม — ไม่สามารถเรียกฟังก์ชัน async จากบริบทที่ตรงกันได้โดยไม่ห่อใน Task ใน Swift สิ่งนี้คอมไพล์ด้วยข้อผิดพลาด ใน Kotlin ต้องเริ่มผ่าน lifecycleScope หรือ viewModelScope การพยายามเรียกฟังก์ชัน suspend จากฟังก์ชันปกติจะไม่คอมไพล์
ไม่ใช่ทุกฟังก์ชันที่ต้องเป็นแบบไม่ตรงกัน งานที่ ใช้ CPU มาก โดยไม่มี I/O ไม่ได้รับประโยชน์จาก async — ควรทำงานบน DispatchQueue ด้วย QoS .userInitiated Async/Await ถูกปรับให้เหมาะสมสำหรับการดำเนินการที่ผูกกับ I/O: เครือข่าย ดิสก์ การรอ
การใช้ .result บนเธรดหลัก (รอผลลัพธ์ของฟังก์ชัน async แบบตรงกัน) นำไปสู่การบล็อก ใน Swift Task.synchronousWait ไม่แนะนำโดย Apple ใน Kotlin runBlocking บนเธรดหลักเป็นปฏิยานุกรม — ใช้ lifecycleScope
หาก Task ไม่ได้ถูกเก็บไว้ในคุณสมบัติของคลาส หลังจากออกจากบริบท Task จะถูก ยกเลิก ใน Swift Task มีขอบเขต — วงจรชีวิตของมันผูกกับบริบทที่สร้าง เก็บ Task ในคุณสมบัติหากคุณต้องการการดำเนินการที่ยาวนาน
คำถามที่พบบ่อย
Async/Await คือโครงสร้างภาษาที่ไม่ต้องสร้างคิว DispatchQueue คือ API ของระบบสำหรับจัดการเธรด Async/await ถูกคอมไพล์เป็นเครื่องสถานะที่ระดับภาษา GCD — เป็น syscall ที่ระดับ OS
ไม่ — await หยุดฟังก์ชันชั่วคราวแต่ปล่อยเธรดสำหรับงานอื่น หลังจากการดำเนินการเสร็จสมบูรณ์ ฟังก์ชันจะเริ่มใหม่บนเธรดใดก็ได้ที่มีในพูล
ได้ — ผ่าน Task.cancel() ใน Swift หรือ Job.cancel() ใน Kotlin การยกเลิกแพร่กระจายไปยังงานย่อยทั้งหมดตาม Structured Concurrency โค้ดตรวจสอบธงการยกเลิกผ่าน Task.isCancelled หรือ ensureActive()
MainActor คือ Actor ที่คุณสมบัติและเมธอดทำงานบนเธรดหลักเสมอ โดยการทำเครื่องหมายฟังก์ชันด้วย @MainActor คุณรับประกันว่าการอัปเดต UI เกิดขึ้นบนเธรดที่ถูกต้อง แทนที่ DispatchQueue.main.async
Async/Await มีใน Swift (iOS 13+), Kotlin (ผ่าน kotlinx.coroutines), Dart (Flutter), JavaScript/TypeScript, Python, C#, Rust และ Go (ผ่าน goroutines ด้วยน้ำตาลเชิงไวยากรณ์)
สรุป
เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร
IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ
อ่านเพิ่มเติม