티스토리 뷰

반응형

Future.microtask()는 Dart에서 비동기 작업을 "가능한 한 빨리" 실행하도록 예약할 때 사용하는 방법이야. 일반적인 Future()나 Future.delayed()와는 조금 다른 용도로 사용돼.


Future.microtask()란?

  • microtask queue에 작업을 추가해,
  • 현재 실행 중인 코드가 모두 완료되면 (즉, 이벤트 루프의 다음 단계로 넘어가기 전에),
  • 가장 먼저 실행되게 만드는 거야.
Future.microtask(() {
  print("나는 microtask!");
});

microtask queue vs event queue

구분 설명

microtask queue 매우 빠르게 실행됨. 현재 작업이 끝나자마자 바로 실행.
event queue 예: Timer, I/O, 사용자 입력 등. 이벤트 루프가 한 사이클 돌고 나서 실행됨.

 

예를 들어:

print('A');

Future.microtask(() => print('B'));

Future(() => print('C'));

print('D');

출력 결과는:

A
D
B
C
  • print('A') → 즉시 실행
  • print('D') → 즉시 실행
  • print('B') → microtask이므로 D 다음에 실행
  • print('C') → 일반 Future이므로 microtask보다 나중에 실행

언제 쓰면 좋을까?

  • 빌드 이후에 무언가 실행하고 싶을 때 (예: initState에서는 context 접근이 불안정할 때)
  • 프레임워크의 초기 작업들이 끝난 직후에 실행하고 싶을 때
  • 다른 비동기 작업보다 우선 실행하고 싶을 때

microtask 사용 예

  @override
  void initState() {
    super.initState();
    
    Future.microtask(() {
      if (mounted) {
        context.read<ItemProvider>().loadItemStatusCountsByGroup();
      }
    });
  }

위 코드는 위젯이 완전히 마운트된 이후, 최대한 빠르게 loadItemStatusCountsByGroup()를 실행하고 싶은 거야.

  • initState()나 didChangeDependencies() 내에서 context 관련 작업을 안전하게 실행하려고 할 때 자주 사용됨.
  • setState()를 호출하기에 안전한 시점이기도 해.

 

Dart 비동기 처리의 기본 구조

Dart는 싱글 쓰레드 기반이지만 비동기 처리를 위해 이벤트 루프(Event Loop) 와 두 가지 큐(queue)를 사용해.

1. Microtask Queue

  • Future.microtask()나 scheduleMicrotask()로 추가됨
  • 우선순위가 높음 – 현재 코드 실행이 끝나면 바로 실행됨
  • 이벤트 큐보다 먼저 실행됨

2. Event Queue

  • Future(), Timer, I/O, 사용자 입력 등으로 추가됨
  • microtask가 다 처리된 후 실행됨

 

예시로 이해하기

import 'dart:async';

void main() {
  print('A');

  Future(() => print('B'));             // Event queue
  Future.microtask(() => print('C'));   // Microtask queue
  scheduleMicrotask(() => print('D'));  // Microtask queue
  Future(() => print('E'));             // Event queue

  print('F');
}

출력 순서

A
F
C  // microtask
D  // microtask
B  // event queue
E  // event queue

 

왜 microtask를 써야 할까?

주 용도 1: 위젯 라이프사이클 중 안전한 타이밍

initState() 안에서 context.read() 또는 setState() 호출은 조심해야 해. 이럴 땐 microtask로 밀어서 다음 프레임에서 실행되도록 해줘.

@override
void initState() {
  super.initState();

  Future.microtask(() {
    if (mounted) {
      context.read<SomeProvider>().fetchData();
    }
  });
}

 

주 용도 2: 비동기 로직의 정확한 순서 제어

void main() {
  Future(() => print('Event'));
  Future.microtask(() => print('Microtask'));
}

→ 결과는 항상 Microtask가 먼저야.


주의할 점

  1. 무한 루프 조심: microtask 안에서 또다시 microtask를 예약하면 빠져나올 수 없어.
  2. 너무 남발 금지: 모든 비동기를 microtask로 만들면 CPU를 독점할 수도 있음.

요약

비교 대상 Future.microtask Future()

위치 microtask queue event queue
실행 시점 현재 코드 끝난 후 즉시 다음 이벤트 루프 주기
우선순위 높음 낮음
사용 예 위젯 초기화 이후 실행, 빠른 처리 필요할 때 일반 비동기 로직 처리

 

반응형
댓글
공지사항