[angular] Promise를 이용한 Service와 Compnent의 HTTP 데이터 처리

4 분 소요

출저 및 참고 사이트 :

https://programmingsummaries.tistory.com/325
https://one-it.tistory.com/entry/Promise-%EC%A0%95%EB%A6%AC-asyncawait-%EC%82%AC%EC%9A%A9%EB%B2%95-then%EA%B3%BC%EC%9D%98-%EC%B0%A8%EC%9D%B4

Javascirpt Pormise

  • Promise 패턴을 사용하면, 비동기적인 작업들을 순서대로, 순차대로 진행하거나, 병렬로 진행할수 있게된다.
  • 현재 Promise 패턴은 ECMA Script 6 스펙에 정식으로 포함되었다.

Promise 기초 예제)

//Promise 선언
var _promise = function (param) {

	return new Promise(function (resolve, reject) {

		// 비동기를 표현하기 위해 setTimeout 함수를 사용 
		window.setTimeout(function () {

			// 파라메터가 참이면, 
			if (param) {

				// 해결됨 
				resolve("해결 완료");
			}

			// 파라메터가 거짓이면, 
			else {

				// 실패 
				reject(Error("실패!!"));
			}
		}, 3000);
	});
};

// new Promise로 Promise 가 생성되는 직후부터 resolve 나 reject가 호출 되기 전까지의 순간을 pending 상태라고 볼 수 있다.
// 이후 비동기 작업이 마친 뒤 결과물을 약속대로 잘 줄 수 있다면

// 첫번째 파라메터로 주입되는 resolve 함수를 호출하고, 실패했다면 두번째 파라메터로 주입되는 reject 함수를 호출한다.



//Promise 실행
// _promise() 를 호출하면 Promise 객체가 리턴된다.
_promise(true)
.then(function (text) {
// Promise 객체에는 정상적으로 비동기 작업이 완료되었을때 호출하는 then 이라는 API 가 존재한다.

	// 성공시 호출할 함수
	console.log(text);
}, function (error) {
	// 실패시 호출할 함수
	console.error(error);
});




var _promise = function (매개변수) {
    return new Promise(function (resolve, reject)) {
         동기적으로 동작하는 함수, 코드
    }
}


_promise(매개변수).then( { 성공시 처리함수 구현}, {실패시 처리함수 구현 } )


Primise 선언부

  • pending : 아직 약속을 수행 중인 상태(fullfilled 혹은 reject가 되기 전)
  • fulfilled : 약속(promise)이 지켜진 상태
  • rejected : 약속(promise)가 어떤 이유에서 못 지켜진 상태
  • settled : 약속이 지켜졌든 안지켜졌든 일단 결론이 난 상태



체이닝형태로 연결된 상태에서 비동기 작업이 중간에 에러가나면 처리 Promise.catch API



여러 프로미스가 모두 완료될 때 실행 Promise.all API



프로미스의 async 와 await

  • 비동기 처리르 없이 코드를 동작하면 undefined 가 출력되는 경우가 있다.
  • Promise를 반환하는 함수 반환값을 사용하기 까지 코드를 지연시키기 위해 async, await 를 사용한다.

Async, await 활용 예제)

const sampleFunc = async () => {
    const result = await asyncFunc() // asyncFunc 함수는 Promise 객체를 반환한다.

    // asyncFunc() 함수의 실행결과가 반한되어 result에 할당되기 전까지, await 키워드가 console.log 함수의 실행을 지연시켜준다.

    console.log(result)

    // Proimise 객체를 반환하는 함수 asyncFunc앞에 await 를 붙이고, 이를 포함하는 함수 앞에 async를 붙여준다.

    // await 키워드를 쓰려면 반드시 async 키워드로 선언된 함수 내부여야 한다.


}


then 과 async/await 의 차이

  • then : { } 코드 블록 밖의 함수는 동기화 불가
  • async / await : { } 코드 블록 밖의 함수도 동기화가 진행됨
  • async/await 를 사용하면 promise.then().catch() 처럼 reject를 잡아낼 수 없기 때문에 try catch 문을 사용해야 한다.


출저 및 참고 사이트 :

https://blog.eunsatio.io/develop/Angular-HttpClient%EC%9D%98-%ED%94%84%EB%A1%9C%EB%AF%B8%EC%8A%A4%ED%99%94,-%EA%B7%B8%EB%A6%AC%EA%B3%A0-HttpInterceptor


Angular HttpClient 라이브러리를 이용한 Promise

기본적인 Http 요청 예제)

constructor(
    private http: HttpClient
) {}
 
public getData(): void {
    this.http.get('request url')
    .subscribe((data: any): void => {
        //do somthing with data
    }, error => {
        //handle error
    });
}
  • subscribe 메서드를 이용해 데이터를 받아 처리
  • subscribe의 두 번째 인자는 에러를 처리하는 콜백 함수
  • 단점 : 콤포넌트에서 직접 Http 통신을 하는 것보다 서비스로 따로 빼서 관리하는 것이 유지보수 측면에서 좋다. (MVVM 패턴)

서비스에서 HTTP 메소드 처리 후, Component 로 데이터 전달

  • Component를 콜백호출로 데이터 처리를 하면, 코드가 길어지니 HTTP 통신 메소드를 Promise로 만들어서 Component 에게 데이터를 전달하는 방식으로 한다.



HttpClient 에서 제공하는 toPromise() 메서드 사용 예제)

Service.TS 파일

constructor(
    private http: HttpClient
) {}
 
public async getData(): Promise<any> {
    return await this.http.get('request url').toPromise();
    //or return await this.http.get('request url').toPromise() as Data;
}


Component.TS 파일

any_service : Any_service;
this.any_service.getData().then(value => 전달받은  처리 구현 )




Promise 로 HTTP 통신을 하면 콜백 이벤트가 한번만 발생해서 (1회성), Subscribe 로 해줘야 한다.

  • Promise 는 콜백 이벤트가 한번만 발생하고, Subscribe 는 콜백이벤트가 제한없이 발생해서 HTTP 통신으로 컴포넌트에 데이터에 넘겨줄때에는 Subscribe 로 넘겨주어야 한다.



앵귤러 HTTP 통신 처리과정. (Rx 패턴 사용)

angular_http_process.png


Http통신을 완료하고, 컴포넌트에서 subscribe로 옵저버블 객체 이벤트를 구현할때, router.navigate 로 페이지를 이동시킬 수 있다.

  openDeleteDialog():void{
    const dialogRef = this.dialog.open(DeleteDialog, { width: '300px', disableClose: true })
      .afterClosed()
      .subscribe(result =>{
        if(result = true){
          // 다이얼로그 응답 결과가 true, 즉 삭제 확인 버튼을 눌렀으면

          this.boardService.deleteBoard(this.postIdx).subscribe(data => { this.router.navigate(['/BoardList']) });
          // 현재 idx 게시글 수정(state=0)을 API에 요청
          // sbucribe() : HTTP 통신이 완료되면 navigate 메소드로 /boardList URL로 이동

        }
    });


보안 문제 등으로 http request url 에 header 를 붙여서 처리하고 싶으면 HttpHeaders 모듈 사용



Http 요청받으면 intercept -> 새로운 헤더를 붙여 복제 및 요청하는 방법 : HttpInterceptor



Promise 와 Observable 차이점

출저 및 참고 사이트 :

https://moaimoai.tistory.com/309

https://blog.briebug.com/blog/what-is-the-difference-between-promises-and-observables



공통점 :

  • 둘다 비동기적인 함수를 동기화해서 사용할때 사용한다.

차이점 :

  • Promise
    • 하나의 값에 대해 resolve 하거나 reject 한다.
    • 한번에 하나의 값에 대해서만 async 비동기 처리를 한다.
    • 한번 완료된 async 값을 resolve 하고나면 더이상 사용이 불가능하고 취소를 할수 없다.
  • Observable
    • 다수의 비 동기적인 값들을 처리할 수 있다.

    • 다수의 비 동기적인 값, 이벤트 스트림을 처리할때 사용한다.

    • 많은 task나 value의 값들을 처리할 때 사용한다. 매 시간마다 pipe의 입구로 자동적으로 들어오는 값들을 처리할때 사용한다.

    • 언제든지 값을 push 할수 있고, subscribe로 자동적으로 처리할 수 있다.

    • 인풋값이 바뀌거나 특정시간마다 반복될 때 , 모든 자식 컴포넌트에게 값을 전달하고 싶을 때, 웹 소켓이 notification 을 푸시하고 싶을때 사용한다.

    • unsubscribe 를 사용하면 언제든지 이벤트 자동 등록을 취소할 수 있다.

    • 가장 중요한 부분은 rx/js 의 오퍼레이터를 제공한다는 것이다.

    • map, filter, switchMap, combineLatest 의 오퍼레이터들을 pipe로 사용할 수 있고, subscribe를 하기전에 값을 transform 할수도 있다.


Promise 동작 방식

async_promise.png



Observable 동작 방식

async_observable.png



연속된 Observable 동작 방식

  • Subscribe 에서 observable을 다른 Subscribe로 넘겨준다.
  • Subject : 다른 subscribe에서 next 함수로 넘겨받은 observable

async_observable_cahin.png