반응형
Jake Seo
제이크서 위키 블로그
Jake Seo
전체 방문자
오늘
어제
  • 분류 전체보기 (715)
    • 일상, 일기 (0)
    • 백준 문제풀이 (1)
    • 릿코드 문제풀이 (2)
    • 알고리즘 이론 (10)
      • 기본 이론 (2)
      • 배열과 문자열 (8)
    • 데이터베이스 (15)
      • Planet Scale (1)
      • MSSQL (9)
      • 디비 기본 개념 (1)
      • SQLite 직접 만들어보기 (4)
    • 보안 (7)
    • 설계 (1)
    • 네트워크 (17)
      • HTTP (9)
      • OSI Layers (5)
    • 회고 (31)
      • 연간 회고 (2)
      • 주간 회고 (29)
    • 인프라 (52)
      • 도커 (12)
      • AWS (9)
      • 용어 (21)
      • 웹 성능 (1)
      • 대규모 서비스를 지탱하는 기술 (9)
    • 깃 (7)
    • 빌드 도구 (7)
      • 메이븐 (6)
      • 그레이들 (0)
    • Java (135)
      • 이펙티브 자바 (73)
      • 자바 API (4)
      • 자바 잡지식 (30)
      • 자바 디자인 패턴 (21)
      • 톰캣 (Tomcat) (7)
    • 프레임워크 (64)
      • next.js (14)
      • 스프링 프레임워크 (28)
      • 토비의 스프링 (6)
      • 스프링 부트 (3)
      • JPA (Java Persistence API) (5)
      • Nest.js (8)
    • 프론트엔드 (48)
      • 다크모드 (1)
      • 노드 패키지 관리 매니저 (3)
      • CSS (19)
      • Web API (11)
      • tailwind-css (1)
      • React (5)
      • React 새 공식문서 요약 (1)
      • HTML (Markup Language) (5)
    • 자바스크립트 (108)
      • 모던 자바스크립트 (31)
      • 개념 (31)
      • 정규표현식 (5)
      • 코드 스니펫 (1)
      • 라이브러리 (6)
      • 인터뷰 (24)
      • 웹개발자를 위한 자바스크립트의 모든 것 (6)
      • 팁 (2)
    • Typescript (49)
    • 리눅스와 유닉스 (10)
    • Computer Science (1)
      • Compiler (1)
    • IDE (3)
      • VSCODE (1)
      • IntelliJ (2)
    • 세미나 & 컨퍼런스 (1)
    • 용어 (개발용어) (16)
      • 함수형 프로그래밍 용어들 (1)
    • ORM (2)
      • Prisma (2)
    • NODEJS (2)
    • cypress (1)
    • 리액트 네이티브 (React Native) (31)
    • 러스트 (Rust) (15)
    • 코틀린 (Kotlin) (4)
      • 자바에서 코틀린으로 (4)
    • 정규표현식 (3)
    • 구글 애널리틱스 (GA) (1)
    • SEO (2)
    • UML (2)
    • 맛탐험 (2)
    • 리팩토링 (1)
    • 서평 (2)
    • 소프트웨어 공학 (18)
      • 테스팅 (16)
      • 개발 프로세스 (1)
    • 교육학 (1)
    • 삶의 지혜, 통찰 (1)
    • Chat GPT (2)
    • 쉘스크립트 (1)
    • 컴파일 (2)
    • Dart (12)
    • 코드팩토리의 플러터 프로그래밍 (4)
    • 플러터 (17)
    • 안드로이드 스튜디오 (1)
    • 윈도우즈 (1)
    • 잡다한 백엔드 지식 (1)
    • 디자인 패턴 (1)

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • 스프링 검증
  • Java
  • bean Validation
  • 외래키 제약조건
  • 작업기억공간
  • 빈 검증
  • 자바 디자인패턴
  • 메이븐 페이즈
  • serverless computing
  • Pre-rendering
  • 자바
  • 이펙티브 자바
  • 메이븐 라이프사이클
  • item9
  • Javadoc 자바독 자바주석 주석 Comment
  • 추상 팩터리 패턴
  • item8
  • prerendering
  • 러스트
  • 프로그래머의 뇌
  • 슬로우 쿼리
  • 자바스크립트 면접
  • MSSQL
  • NEXT JS
  • rust
  • Next.js
  • 도커공식문서
  • 자료구조
  • 자바스크립트 인터뷰
  • 싱글톤
  • next js app
  • 이펙티브 자바 item9
  • 자바 검증
  • 플라이웨이트패턴
  • try-with-resources
  • 팩터리 메서드 패턴
  • 토비의 스프링
  • 싱글턴
  • 이펙티브자바
  • 참조 해제
  • 메이븐 골
  • item7
  • 서버리스 컴퓨팅
  • 디자인패턴
  • 느린 쿼리
  • 객체복사
  • 싱글톤 패턴
  • 알고리즘
  • 자바스크립트
  • pnpm

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
Jake Seo

제이크서 위키 블로그

코드팩토리의 플러터 프로그래밍

코드 팩토리의 플러터 프로그래밍 - 다트 언어 마스터하기, 3장 다트(Dart) 비동기 프로그래밍

2023. 10. 21. 23:55

코드 팩토리의 플러터 프로그래밍 - 다트 언어 마스터하기, 3장 다트(Dart) 비동기 프로그래밍

"이 글은 골든래빗 《코드 팩토리의 플러터 프로그래밍》의 03장 써머리입니다."

동기 vs 비동기 프로그래밍

  • 비동기 프로그래밍은 요청한 결과를 기다리지 않아서 순서대로 실행된다는 보장이 없다.
  • 일단 요청을 보내놓고 기다린다.
  • UI 프로그래밍에서는 UI 가 블록되지 않도록 하는데 중요한 역할을 한다.
  • 동기 프로그래밍만 사용해야 한다면, 시간이 걸리는 작업에서 UI의 반응이 멈춰버린다.
  • 네트워크 API 응답을 받거나, 큰 계산, 인코딩 등이 긴 작업에 해당한다.

Future

  • 비동기 프로그래밍에 쓰이는 Future 클래스는 이름처럼 미래에 받아올 값을 의미한다.
Future<String> name;
Future<int> number;
Future<bool> isOpen;

Future.delayed()

  • 주어진 시간동안 아무것도 하지 않고 기다린다.
  • 아래 코드에서 중간에 위치한 1 + 1 = 2 가 가장 나중에 나온다.
  • 위에서 설명한 비동기 프로그래밍의 특성으로 순서대로 실행된다는 보장이 없다.
void main() {
  addNumbers(1, 1);
}

void addNumbers(int number1, int number2) {
  print('$number1 + $number2 계산 시작');

  Future.delayed(Duration(seconds: 3), () {
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}

// 출력 결과:
/*
1 + 1 계산 시작
1 + 1 코드 실행 끝
1 + 1 = 2
*/

async 와 await

  • 비동기 프로그래밍을 순서대로 실행시키는 방법이다.
  • 인간은 순서대로 실행되는 게 보장되어야 생각하기 편하다.
  • 함수 파라미터 끝에 async 가 붙었고, Future.delayed 앞에 await 이 붙었다.
void main() {
  addNumbers(1, 1);
}

void addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작');

  await Future.delayed(Duration(seconds: 3), () {
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}
// 출력 결과
/*
1 + 1 계산 시작
1 + 1 = 2
1 + 1 코드 실행 끝
*/

async, await 을 써도 여전히 비동기

  • async, await 을 쓰면 동기와 무슨 차이냐고 생각할 수 있지만, 여전히 비동기이다.
  • async 함수 영역 안에서만 동기처럼 실행되는 것이고, 밖에선 아니다.
    • addNumbers() 함수의 관점에서는 동기처럼 실행된다.
    • main() 함수의 관점에서는 비동기처럼 실행된다.
  • 여전히 CPU 리소스의 낭비를 막을 수 있다.
  • main() 자체도 async, await 으로 만들면 한 계층 밖으로 비동기 동작방식을 또 동기로 꺼내올 수 있다.
void main() {
  addNumbers(1, 1);
  addNumbers(2, 2);
}

Future<void> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작');

  await Future.delayed(Duration(seconds: 3), () {
    print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');
}
// 출력 결과
/*
1 + 1 계산 시작
2 + 2 계산 시작
1 + 1 = 2
1 + 1 코드 실행 끝
2 + 2 = 4
2 + 2 코드 실행 끝
*/

결과값 반환받기

void main() async {
  final result = await addNumbers(1, 1);
  print('결괏값 $result');
  final result2 = await addNumbers(2, 2);
  print('결괏값 $result2');
}


Future<int> addNumbers(int number1, int number2) async {
  print('$number1 + $number2 계산 시작!');

  await Future.delayed(Duration(seconds: 3), () {
      print('$number1 + $number2 = ${number1 + number2}');
  });

  print('$number1 + $number2 코드 실행 끝');

  return number1 + number2;
}
// 출력 결과
/*
1 + 1 계산 시작!
... 3초 딜레이 ...
1 + 1 = 2
1 + 1 코드 실행 끝
결괏값 2
2 + 2 계산 시작!
... 3초 딜레이 ...
2 + 2 = 4
2 + 2 코드 실행 끝
결괏값 4
*/

Stream

  • Future 는 값을 딱 한번 반환받는 경우
  • 지속적으로 반환받는다면 Stream 을 사용
  • Stream 은 한번 listen 하면 Stream 에 주입되는 모든 값들을 지속적으로 받아옴
  • 다만 for, await 도 데이터가 한번 이상 반환되는 경우에 적합하므로, 어떤 것이 효율적인지 따져봐야 한다.

Future.wait() 함수는 Future 의 리스트를 매개변수로 받아 비동기 작업을 동시에 수행하고 응답값을 요청 보낸 순서대로 저장해둔다.

Stream 기본 사용법

  • dart:async 패키지를 불러와야 한다.
  • StreamController 내부의 stream 을 listen() 해야 한다.
import 'dart:async';

void main() {
  final controller = StreamController(); // StreamController 선언
  final stream = controller.stream; // Stream 가져오기

  // Stream 에 listen() 함수를 실행하면 값이 주입될 때마다 콜백 함수를 실행
  final streamListener1 = stream.listen((val) {
    print(val);
  });

  // stream 에 값 주입
  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
  controller.sink.add(4);
}

// 출력 결과
/*
1
2
3
4
*/

브로드캐스트 스트림

  • 하나의 스트림에 리스너를 여러개 등록하고 싶을 때 사용한다.
  • 브로드캐스트 스트림이 아니라면, 두번째 리스너 등록에 Uncaught Error: Bad state: Stream has already been listened to. 에러가 표출된다.
  • 아래 코드의 경우, sink 에 add() 메서드가 한번 일어날 때마다 두개의 리스너가 반응한다.
  • JS 의 경우 addEventListener(event, () {}) 로 이벤트를 등록하면 이벤트를 여러개 등록할 수 있어 브로드캐스트 스트림과 흡사하게 된다.
    • 다만 .onclick = () => {} 와 같은 방식으로 등록하면 이벤트가 최대 1개만 등록된다.
import 'dart:async';

void main() {
  final controller = StreamController();
  final stream = controller.stream.asBroadcastStream(); // BroadcastStream 가져오기

  final streamListenerA = stream.listen((val) {
    print('listener A $val');
  });

    final streamListenerB = stream.listen((val) {
    print('listener B $val');
  });

  controller.sink.add(1);
  controller.sink.add(2);
  controller.sink.add(3);
}

// 출력 결과

/*
listener A 1
listener B 1
listener A 2
listener B 2
listener A 3
listener B 3
*/

함수로 Stream 반환하기

  • StreamController 를 사용하지 않고 Stream 을 반환하는 함수를 작성할 수 있다.
  • 반환 타입을 Stream 으로 설정하고, async* 로 함수를 선언하고, yield 키워드로 값을 반환하면 된다.
  • 아래의 calculate() 는 Stream 을 numberOfStream 의 크기만큼 반환한다.
    • 반환된 모든 Stream 에 listen() 메서드를 적용시킨다.
import 'dart:async';

Stream<String> calculate(int numberOfStream) async* {
  for (int i=0; i<numberOfStream; i++) {
    // controller.sink.add() 를 이용했던 것처럼 yield 를 이용해 값 반환
    yield 'i = ${i+1}';
    await Future.delayed(Duration(seconds: 1));
  }
}

void playStream() {
  calculate(3).listen((val) {
    print(val);
  });
}

void main() {
  playStream();
}

// 출력 결과
/*
i = 1
i = 2
i = 3
*/

요약

  • 비동기 프로그래밍은 UI 에서 블록이 일어나지 않도록 리소스가 막히는 상황을 방지하는데 유용
  • Future: 비동기로 '한번' 값을 받을 때 유용
  • async await: 비동기 작업을 함수 내에서 순차적으로 실행시킬 때 유용
  • Stream: listen() 을 통해 비동기 응답 이벤트가 발생할 때마다 지속적으로 동작할 콜백 함수 정의 가능
    • async* 과 yield 를 이용한 함수로 Stream 타입을 반환할 수도 있다.
반응형
저작자표시 비영리 (새창열림)

'코드팩토리의 플러터 프로그래밍' 카테고리의 다른 글

코드 팩토리의 플러터 프로그래밍 - 플러터 기본 다지기, 4장 플러터 입문하기  (1) 2023.10.29
코드 팩토리의 플러터 프로그래밍 - 다트 언어 마스터하기, 2장 다트(Dart) 객체지향 프로그래밍  (1) 2023.10.15
코드 팩토리의 플러터 프로그래밍 - 다트 언어 마스터하기, 1장 다트 (Dart) 입문하기  (0) 2023.10.08
    '코드팩토리의 플러터 프로그래밍' 카테고리의 다른 글
    • 코드 팩토리의 플러터 프로그래밍 - 플러터 기본 다지기, 4장 플러터 입문하기
    • 코드 팩토리의 플러터 프로그래밍 - 다트 언어 마스터하기, 2장 다트(Dart) 객체지향 프로그래밍
    • 코드 팩토리의 플러터 프로그래밍 - 다트 언어 마스터하기, 1장 다트 (Dart) 입문하기
    Jake Seo
    Jake Seo
    ✔ 잘 보셨다면 광고 한번 클릭해주시면 큰 힘이 됩니다. ✔ 댓글로 틀린 부분을 지적해주시면 기분 나빠하지 않고 수정합니다. ✔ 많은 퇴고를 거친 글이 좋은 글이 된다고 생각합니다. ✔ 간결하고 명료하게 사람들을 이해 시키는 것을 목표로 합니다.

    티스토리툴바