본문 바로가기
삽질하는 개발자 hashblown

프론트엔드 개발자의 TIL #017

by hashblown 2019. 11. 25.

TIL #017

191125 월

 


오늘 배운 점

<Flutter>

1. Future

  • 어제 작성한 TIL부터 Async coding 시리즈 공부를 시작했고, 그 2번째가 Future이다.
  • Future는 Dart가 비동기 작업을 위해 가지고 있는 가장 기본적인 API다. (다른 언어에서 같은 역할을 하는 예로 Promise가 있다.) Future를 데이터를 위한 작은 선물상자라고 생각하면, 처음 닫혀 있다가(Uncompleted), 시간이 지나 열리면(Completed) 데이터를 가지고 있거나(with data), 에러를 가지고 있다(with error). 이렇게 3가지 상태의 Future가 순환되면서 코드가 진행된다.
RaisedButton(
	onPressed: () {
    	final myFuture = http.get(url);
        myFuture.then((resp) {
        	setImage(resp);
        });
    }
    child: Text('Click'),
)
  • 위 코드를 해석해보면, 먼저 Event loop가 사용자의 Tap 이벤트를 받아 Tap handler가 호출을 받는다. onPressed는 http 라이브러리를 이용하여 요청을 만들고, 이에 따라 Future를 받는다. Future는 닫힌 상태로 오기 때문에 then을 사용하여 나중에 상자가 열릴 때를 위한 callback을 등록한다. Event loop가 계속 움직이며 다른 이벤트들을 처리하는 동안 Future는 닫힌 채로 있는다. 그러다 데이터가 오면 http 라이브러리가 이를 받아 Future에 넣으면 상자가 열리게 된다. 이때 등록해뒀던 callback이 실행되는 것이다.
  • Future의 instance를 얻는 방법은 무엇일까? 일반적인 비동기 작업들은(http나 shared preference 등) 이미 future를 생성해주는 라이브러리를 가지고 있기 때문에 직접적으로 얻기는 어렵다. 그래서 생성자(constructor)를 사용할 수 있다.
//기본값
final myFuture = Future (() {
	//처음엔 uncompleted, 나중에 함수 실행하면 데이터 들어감
    print();
    return 12;
});

//이미 값을 알고 있는 상태인 경우
final myFuture = Future.value(12);

//에러 처리
final myFuture = Future.error(Exception());

//구체적으로 정해진 시간까지 기다렸다가 함수 실행
final myFuture = Future.delayed(
	Duration(seconds: 5),
    () => 12,
);
  • 이제 생성자를 적용하여 코드를 작성해보면 다음과 같다.
import 'dart: async';

void main() {
	Future<int>.delayed(
      Duration(seconds: 3),
      () { return 100; },
    ).then((value) {
    	print(value);
    }).catchError(
      (err) {
      	print('Caught $err');
      },
      test: (err) => err.runtimeType == String,
    ).whenComplete(() {
      print('All finished!');
    });
    
    print('Waiting..');
}
  • main 함수가 끝까지 실행되어 Waiting을 출력하고 + 3초의 시간이 흐르고 나면 닫혀있던 Future는 100이라는 값으로 열린다. Future의 값을 사용하고 싶을 때 then을 활용한다. 여기에 앞서 언급한 대로,  Future가 값이 있는 상태로 완료되었을 때 실행할 callback을 등록한다. 이 callback은 Future의 type에 맞는 단일 매개변수를 가진 함수로 구성된다. 이렇게 하면 Future가 완료될 때 해당 값으로 함수가 실행된다.
  • Future가 값대신 에러가 있는 채로 완료되면 catchError를 사용한다. 데이터 대신 에러를 처리할 뿐, then과 같은 메커니즘으로 작동한다. test 메서트를 실행하여 callback을 실행하기 전에 에러를 확인할 수도 있다.
  • Future가 값이든 에러든 완료가 되면 실행할 메서드는 whenCompleted를 사용한다. try catch finally에서 finally와 유사한 역할이다.
final myFuture = _fetchNameForId(12)
  .then((name) =>_fetchCountForName(name))
  .then((count) => print(count));
  • then은 자체적으로 Future을 반환하기도 하기 때문에, 여러 async를 처리할 때 type이 다르더라도 연쇄적으로 then을 연결하는 코드를 짤 수도 있다.
@override
Widget build(BuildContext context) {
  return FutureBuilder<String>(
  	future: _fetchNetworkData(),
    builder: (context, snapshot) {
      if (snapshot.hasError) {
      	return Text('There was an error.');
      } else if (snapshot.hasData) {
      	return Text(
          json.decode(snapshot.data)['delay_was'],
        );
      } else {
      	return Text('No value yet!');
      }
    },
  );
}
  • 이를 Flutter에 적용하면 위와 같다. stateful 위젯을 만들어서 future를 생성하고, 완료 상태와 에러를 확인하고, setState를 호출하는 등 수작업으로 만들 수도 있지만, FutureBuilder를 이용하여 자동적으로 하위 요소를 만들게 할 수도 있다. context와 snapshot의 2가지만 있으면 된다. snapshot이 에러를 가지고 있는지, 데이터를 가지고 있는지에 따라 각각 메서드를 실행할 수 있고, 둘 다 아닌 경우, 즉 여전히 기다리는 상태에서의 메서드를 실행하여 Future가 어떤 상태인지를 알 수 있다.

내일 배울 점

<Flutter>

1. 예전에 간단하게 공부했던 Stream을 이어서 자세히 공부할 예정이다.

 

<학교 전공>

1. 범주형자료분석 수업에서 배운 내용을 정리하고, 곧 제출해야 할 기말레포트에 필요한 데이터셋 조사를 시작해야겠다.

2. 데이터마이닝 수업에서 작성한 코드들을 정리해봐야겠다.


더보기

- 무기력한 날들도 있지만, 생각하는 대로 살기 위해 노력해야지..

 

댓글