프로미스(Promise)
싱글쓰레드인 자바스크립트에서 비동기 처리를 위해서 콜백(callback)을 사용해왔다.
덕분에 비동기 처리를 온전히 해낼 수 있었지만 이런 콜백이 사용되는 경우가 많아지면서 단점이 드러났다.
그 단점은 비동기 처리를 순차적으로 실행할 필요가 있는 경우에 비동기 처리를 중첩시켜서 표현하므로 에러, 예외처리가 어렵다는 것과 중첩으로 인한 복잡도가 증가하는 것이 이다.
크게 이 두 가지의 단점을 해결하기위해 프로미스가 예전부터 라이브러리로 생겨났고, 이것을 ES6에서는 언어적 차원에서 지원하게 되었다.
Promise를 이해하기 위해 여러 블로그를 돌아다니며 찾아본 결과 핵심은 이 프로미스의 목적만 머릿속에 집어넣는 것이고, 딱 한 번만 따라 쳐보면 이해가 된다.
"비동기에서 성공과 실패를 분리해서 메서드를 수행한다."
예외 처리 실패 예시
1 2 3 4 5 6 | try { setTimeout(() => { throw 'Error!'; }, 1000); } catch (e) { console.log('에러를 캐치하지 못한다..'); console.log(e); } | cs |
try-catch에서 비동기 함수의 콜백메서드에서 에러를 만들지만 catch하지 못한다.
(setTimeout()함수의 콜백은 이벤트큐에 있다가 콜스택이 비어지면 실행되기 때문)
고로 콜백메서드의 중첩은 에러 처리가 힘들다.
프로미스 생성, 실행
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | //프로미스 생성 const promise1 = function(param){ return new Promise(function(resolve,reject){ if(param){ resolve("바보"); } else{ reject("아닌데"); } }); } //프로미스 실행 promise1(true).then(function(result){ console.log(result);//바보 },function(err){ console.log(err);//아닌데 }); |
프로미스의 생성 방법은 new Promise((resolve, reject){...}) 로 생성하는 방법이다.
promise1 함수를 보면 프로미스를 리턴하는데 이것은 프로미스안에서 비동기함수를 실행하고(위의 예제는 단순히 파라미터로 true, false) 성공했을 때 resolve()를 실행하고 실패 또는 에러가 났을 때 reject()를 실행한다.
그러면 resolve()랑 reject()는 나중에 함수를 실행할 때 .then(success, fail)메서드로 수행하면 된다.
* 프로미스는 상태를 갖는다. (쉽게 fulfilled, rejected 두 개만 기억, fulfilled상태면 resolve()실행, rejected면 reject()실행)
결국 비동기함수를 만들어서 사용해야할 때 프로미스 객체를 리턴하게 만들어서 사용하면 콜백 헬(콜백 중첩)을 방지할 수 있고 에러처리를 수월하게 할 수 있다는 이야기다.
누군가 만든 비동기함수 역시 프로미스 객체를 리턴하게 만들어 놨으므로 promise를 실행(.then 또는 .catch)하면 된다.
비동기 함수 중간에 에러가 난다면..? Promise.catch()
1 2 3 4 5 6 7 8 9 | asyncThing1() .then(function() { return asyncThing2();}) .then(function() { return asyncThing3();}) .catch(function(err) { return asyncRecovery1();}) .then(function() { return asyncThing4();}, function(err) { return asyncRecovery2(); }) .catch(function(err) { console.log("Don't worry about it");}) .then(function() { console.log("All done!");}); | cs |
비동기 메서드가 프로미스 객체를 리턴하면 계속해서 .then, .catch하는 식으로 체이닝이 가능하다.
.catch는 비동기 메서드중에 에러가 나면 캐치가 가능하게 해준다.
<그림 출처 : http://programmingsummaries.tistory.com/325>
그림이 너무 좋아서 가져왔다. 성공(녹색선)과 실패(빨간선)했을 때는 잘 따라오면서 보면 이해가 된다.
여러 개의 프로미스가 모두 완료되었을 때 실행하는 방법
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | const param = true; const promise1 = new Promise(function(resolve,reject){ if(param){ resolve("바보"); } else{ reject("아닌데"); } }); const promise2 = new Promise(function(resolve,reject){ if(param){ resolve("바보2"); } else{ reject("아닌데2"); } }); Promise.all([promise1,promise2]).then(function(values){ console.log("1,2,3 모두완료",values); }); |
Promise.all()을 사용하면 파라미터로 갖는 모든 프로미스가 완료되면 수행하고 프로미스들의 값을 보여준다.
결과=>
1,2,3 모두완료
[바보, 바보2]
참고사이트
http://poiemaweb.com/es6-promise
http://blog.jeonghwan.net/2016/04/28/es6.html
http://programmingsummaries.tistory.com/325
'Javascript > Javascript(ES6)' 카테고리의 다른 글
ES6 이진 탐색 트리 구현하기, 어떻게 특정 값을 빠르게 찾을 수 있을까? (Binary Search Tree, BST) (0) | 2018.02.09 |
---|---|
ES6 바벨(babel)을 이용한 트랜스 파일링(es6 개발환경 구축하는 방법, feat.webpack) (0) | 2018.01.22 |
ES6 자료구조 연결리스트(LinkedList) 구현하기(이중연결리스트, 원형연결리스트) 그리고 의문점.. (0) | 2018.01.18 |
ES6 자료구조 큐(Queue) 구현하기, 우선순위 큐 만들고, 큐 두개로 스택 만들기 (2) | 2018.01.17 |
ES6 자료구조 스택(Stack)만들어보기, 스택 2개로 큐(Queue) 만드는 방법 (0) | 2018.01.14 |