상세 컨텐츠

본문 제목

[Dart] 비동기 프로그래밍

IT/기초

by SINAFLA 2021. 7. 2. 09:42

본문

반응형

 

비동기 처리

  • 비동기 작업은 다른 작업들이 비동기 작업이 완료 되는 것을 기다리는 동안에 하던 것을 완성하도록 한다.

 

작업의 예

  • 네트워크에서 데이터를 가져오기
  • 데이터베이스 연산
  • 파일에서 데이터를 읽기

 

비동기 작업을 위해 Future 클래스와 async, await 키워드를 사용한다. 자바스크립트에서 사용하는 Promise가 Dart에서는 Future와 대응된다. Future와 Promise는 모두 싱글 스레드 환경에서 비동기 처리를 위해 존재한다.

 

Future은 무엇인가

  • future은 어떤 작업 결과 값을 나중에 받기로 약속하는 것이다. 즉 요청한 작업의 결과를 기다리지 않고 바로 다음 작업으로 넘어간다. 그 후 작업이 완료되면 결과를 받는 방식으로 비동기 처리를 한다.
  • future는 상태별로 다른 작업과 마찬가지로 event loop에 의해서 순차적으로 처리된다.
  • 처음 future를 생성하여 작업을 시작하면 uncompleted future가 event queue에 들어간다.
  • 해당 작업이 완료되기 전까지는 다른 작업들이 event queue에 들어가고 event loop에 의해서 꺼내져 처리된다.
  • 그러다가 future가 작업을 끝내면 Completed future가 event queue에 들어가고 event loop에 의해 선택되면 Complete future가 가진 결과 값이나 에러에 대한 처리를 한다.

 

Future 사용해서 서버의 데이터 가져오기

  • 서버에 데이터 요청을 할 때 (API 요청) Future을 이용한다.

 

http 패키지 의존성 추가하기

dependencies:
  http: <latest_version>

 

http 패키지 추가하기

import 'package:http/http.dart' as http;
import 'dart:convert';

 

 

Future을 이용한 서버 데이터 요청 메소드 추가하기

Future<dynamic> getHttpData () async {
	var response = await http.get('https://jsonplaceholder.typicode.com/posts/1');
	return jsonDecode(response);
}

 

  • getHttpData()에서 jsonDecode 메소드를 이용한 이유는 http 통신으로 넘어온 데이터를 Json 타입으로 바꿔주기 위해(Parsing) 사용한다.
  • Future를 이용해서 데이터를 받아서 사용할 경우 StatelessWidget인 경우 FutureBuilder를 이용해 값을 매핑해줘서 화면을 그려준다.
  • 아닌 StatelessWidget이 아닌 StatefulWidget인 경우는 setState() 함수를 이용해 값이 변경되었을 경우 화면을 다시 build() 하게 해준다.
  • setState()를 이용해 프레임워크에 알려줘야 화면을 다시 그려지고, 값 매핑하는 부분에 http으로 받은 데이터로 변경할 수 있다.
  • Future 메소드에 async와 await 키워드를 사용한 이유는 http 통신으로 값을 가지고 오는 Future의 비동기 방식은 시간이 걸리기 때문에 이 작업이 끝날 때까지 기다린다는 걸 명시해준다. 그래서 http 통신을 기다렸다가 값을 넘겨준다.
  • 비동기로 메소드를 여러 개 사용할 수 있다. 여러 개를 사용했을 무작정 async, await 키워드 사용 남발은 안 좋다.

 

import 'package:flutter/material.dart';
import 'dart:convert';

void main() => runApp(MyHome());

class MyHome extends StatelessWidget {
	@override
	Widget build(BuildContext context) {
		return MaterialApp(
			home: Scaffold(
				body: MyTest(),
			),
		);
	}
}

class MyTest extends Statefulwidget {
	@override
	_MyTestState createState() => _MyTestState();
}

class _MyTestState extends State<MyTest> {

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

	Future<dynamic> test1() async {
		return await jsonDecode(http.get('https://jsonplaceholder.typicode.com/posts/1'));
	}
	
	Future<dynamic> test2() async {
		return await jsonDecode(http.get('https://jsonplaceholder.typicode.com/posts/2'));
	}
	
	Future<dynamic> test3() async {
		return await jsonDecode(http.get('https://jsonplaceholder.typicode.com/posts/3'));
	}

	void func() async {
		await test1();
		await test2();
		await test3();
	}

	@override
	Widget build(BuildContext context) {
		return Container(
		);
	}
}

 

 

  • func() 에서 값을 가져 오는 부분에서 모든 future 메소드에 await 를 했다. 이러면 test1()가 끝나고 test2()가 실행되고, test2()가 끝나야 test3()이 실행된다.
  • 이렇게 된다면 정작 데이터를 받아서 처리되는데 시간이 많이 소모된다.
  • Future 메소드를 여러 개 공통으로 묶는 함수가 있는 경우엔 묶어주는 메소드에서는 호출되는 메소드에 await를 할 필요가 없다.
  • 각각 메소드가 기능 별인 경우는 할 필요가 없다.
  • 하지만 메소드의 값을 받아서 처리되는 기능이 있는 경우 연달아 오는 메소드에는 await를 할 필요가 있다.

 

 

반응형

관련글 더보기

댓글 영역