ข้ามไปยังเนื้อหา

Async in Dart

Dart รัน code ของคุณบน single thread พร้อม event loop — model เดียวกับ JavaScript ใน code ปกติไม่มี threading แบบ shared-memory แต่ async operation (network, file, timer) จะรันที่อื่น แล้ว schedule callback บน event loop เมื่อเสร็จ

นี่คือเหตุผลที่ “async” ใน Flutter ไม่ได้แปลว่า “อีก thread” แต่แปลว่า “อย่า block thread เดียวที่เรามี” loop แบบ synchronous ที่ช้าจะ freeze UI แต่การ await network call ไม่ freeze เพราะ thread ว่างพอจะ render frame ระหว่างรอ

flowchart LR
  ui["UI thread
(event loop)"] -->|await fetch| free["thread ว่าง
พอจะ render frame"]
  free -->|response มาถึง| cb["callback ถูก schedule
บน loop"]
  cb --> resume["code ของคุณทำงานต่อ"]
งาน async ปลดปล่อย thread เดียวให้ render ต่อได้

Future<T> คือค่าที่จะมีทีหลัง — ผลของ async operation async/await ให้คุณเขียนโค้ด async ให้อ่านเหมือนโค้ด sequential

Future<User> fetchUser(int id) async {
final response = await http.get(Uri.parse('/users/$id')); // รอ แต่ไม่ block
return User.fromJson(response.body);
}
// เรียกใช้:
Future<void> load() async {
try {
final user = await fetchUser(42);
print(user.name);
} catch (e) {
print('failed: $e'); // future ที่ await จะ throw error ที่ try/catch ได้
}
}

function ที่เป็น async คืน Future เสมอ await แกะค่าข้างในออกมา และที่สำคัญ — error จาก future ที่ await จะโผล่มาเป็น exception ปกติที่ try/catch ได้ ใน Flutter คุณแทบไม่ await ใน build แต่ส่ง Future ให้ FutureBuilder แทน (โมดูลถัดไป)

Stream<T> เหมือน Future ที่ส่งค่า หลายค่า — ลำดับของ event ตามเวลา: ข้อความ web-socket, ค่า sensor, input ของ user, การเปลี่ยนแปลงของ database

Stream<int> ticker() async* { // async* ทำให้เป็น Stream; yield emit ค่า
for (var i = 1; i <= 3; i++) {
await Future.delayed(const Duration(seconds: 1));
yield i; // emit 1, แล้ว 2, แล้ว 3
}
}
// consume ด้วย await-for หรือ .listen:
await for (final tick in ticker()) {
print(tick); // 1, 2, 3 — หนึ่งค่าต่อวินาที
}

การแยก Future/Stream map เข้ากับ Flutter ได้พอดี: async แบบ one-shot → FutureBuilder; stream ของ update → StreamBuilder เข้าใจความต่างนี้ให้ถูกก็เท่ากับเข้าใจ “async ใน Flutter” ไปเกือบหมดแล้ว

ข้อยกเว้นเดียวของ “single thread” คือ isolate — worker แยกที่มี memory ของตัวเอง สื่อสารด้วยการส่ง message (ไม่มี shared state) คุณหยิบมาใช้เฉพาะงานที่หนัก CPU จริง ๆ (parse JSON ก้อนใหญ่, image processing) ที่ไม่งั้นจะทำให้ UI jank Flutter ห่อ case ทั่วไปไว้ใน compute() ซึ่งอยู่ในโมดูล performance

async หมายความว่าอะไรใน execution model ของ Dart?
ความต่างของ Future กับ Stream คืออะไร?
error จาก Future ที่ await โผล่มาอย่างไร?
ควรหยิบ isolate มาใช้เมื่อไร?