지난 시간에 "콜백 함수"라는 디자인 패턴에 대해서 알아봤다.
그러나, 콜백은 길어질 경우 코드가 우측으로 넓어진다는 단점이 존재한다.
=> 콜백 지옥!!
이렇게 우측으로 길어지는 콜백함수 대신 코드가 길어지지 않는 새로운 디자인 패턴이 등장했으니 바로 Promise 디자인패턴이다.
이건 자바스크립트의 새로운 기능이라기보다는 코드/함수 디자인 패턴
일 뿐입니다.
이런거 안써도 코드잘짤 수 있긴 한데, 나오면 알아야하니 아무튼
그럼 일단 어떻게 하는지 알아봅시다.
let 프로미스 = new Promise(); // 성공 or 실패를 판정해주는 기계
프로미스.then(function(){
// 성공시, 실행되는 코드
}).catch(function(){
// 실패시, 실행되는 코드
}).finally(function(){
// 성공이든, 실패든 뭔가 일어났을 때 실행
});
이것이 끝입니다.
new Promise()
문법으로 프로미스라는 변수 오브젝트를 하나 생성하시면 Promise 제작 끝이다.
그럼 이제 프로미스라는 변수에다가 then()
을 붙여서 실행가능하다.
프로미스 안의 코드가 실행이 완료가 되었을 때 then()
함수 내의 코드를 실행시켜준다.
코드가 실행이 실패했을 경우엔 catch()
함수 내의 코드를 실행시켜준다.
마지막으로 옵션으로 finally()
라는 함수도 붙일 수 있다.
이 경우는 코드가 성공하든, 실패하든 둘 중 하나가 실행된 다음에 함수 내의 코드를 실행해준다.
(지금은 프로미스 안에 코드가 암것도 없지만요)
이런 식으로 코드를 차례로 실행할 수 있게 도와주는 디자인 패턴이 바로 Promise
이다.
이거는 혁명이다.
콜백 함수는 뭐가 실행됐을 때, "이거를 실행해주세요~" 밖에 못했는데, Promise
패턴이 등장하면서, 실패했을 경우, 실행될 코드 역시 만들어낼 수 있게 된거다.
콜백함수와는 다르게 순차적으로 뭔가를 실행할 때 코드가 옆으로 길어지지 않는다.
then
함수를 붙여서 순차적으로 실행하니까.
콜백함수는 불가능한 '실패시 특정 코드를 실행해주세요~' 라고 코드를 짤 수 있다. (catch
)
우선 Promise
를 사용해주기 위해서는
new Promise()
안에는 반드시 콜백함수를 하나 넣어줘야 하는데, 그 콜백 함수는 2개의 파라미터를 받는다. 보통 관습적으로 resolve
, reject
라고 쓰는데, 각각 성공과 실패를 나타낸다.
let 프로미스 = new Promise(function(resolve, reject){
});
그리고 아래와 같이 어떤 경우 "성공"이고, "실패"인지를 구분해줘야 한다.
let 프로미스 = new Promise(function(성공, 실패){
// 여기서, 특정 연산을 하든 뭘 하든해서
// 무엇이 성공이고, 실패인지를 설정해줘야 한다.
성공();
// 이 경우 then 구문이 실행된다.
실패();
// 이 경우 catch 구문이 실행된다.
});
" 성공하면 then()
, 실패하면 catch()
를 실행해주세요~ " 라는 코드를 짤 수 있게 도와주는게 바로 Promise
이다.
그럼 Promise는 성공과 실패 상황을 알려줘야겠죠?
그래서 Promise를 를 쉽게 정의하자면 성공&실패 판정기계
이다.
Promise 기계 안에는 아무거나 다 집어넣을 수 있습니다
1 + 1
같은 어려운 연산이 끝나면 성공판정 내려주세요~
페이지 내의 <button>
을 누르면 성공으로 판정해주세요 ~
Ajax 요청으로 서버의 데이터를 가져오면 성공판정, 에러나면 실패판정해주세요~
아무거나 다 집어넣을 수 있습니다.
Promise 안에서 성공/실패를 판정하는 방법은 쉽습니다. 그대로 따라쓰시면 됩니다.
var 프로미스 = new Promise(function(성공, 실패){
성공();
});
프로미스.then(function(){
}).catch(function(){
});
Promise()
안에 콜백함수를 하나 추가해주시면 그 안에서 성공/실패 판정을 내릴 수 있습니다.
성공()
이라고 첫째 파라미터를 함수형태로 작성하면 성공판정이 됩니다.
실패()
라고 둘째 파라미터를 함수형태로 작성하면 실패판정이 됩니다.
위의 코드는 무조건 성공()
을 실행하게 되어있으니 무조건 성공을 판정내리며
그 후엔 이제 then()
안의 코드가 실행이 되겠죠?
실제로 사용하는 예시를 봅시다.
콜백함수로 디자인해놓아도 될 것 같죠? 그럼 그렇게 해도 된다.
근데 저는 콜백보다는 .then()
을 쓰고싶어서 Promise를 한번 활용해보겠습니다.
let 프로미스 = new Promise(function(성공, 실패){
var 어려운연산 = 1 + 1;
성공();
});
프로미스.then(function(){
console.log('연산이 성공했습니다')
}).catch(function(){
});
Promise()
안에 어려운 수학 연산을 해주는 기능을 추가했다.
그리고 그 연산이 완료되면 성공()
코드를 실행하도록 코드를 추가했다.
(일반 코드들은 저렇게 위아래로 나란히 적으면 그냥 차례로 실행됩니다)
기계를 잘 만들어놨으니 then 함수 안에는 프로미스가 성공판정을 내리면, 실행할 코드를 담을 수 있다.
그럼 디자인 끝!!
이제 프로미스 내의 1+1
이라는 어려운 수학연산이 완료되면 성공()
판정을 내리며,
성공시 then()
내의 코드를 실행해줍니다.
이렇게 Promise
를 사용하시면 이상한 콜백함수패턴 대신 멋있는 then
을 사용할 수 있군요.
이렇게 하시면 됩니다.
var 프로미스 = new Promise(function(성공, 실패){
var 어려운연산 = 1 + 1;
실패();
});
프로미스.then(function(){
console.log('연산이 성공했습니다')
}).catch(function(){
console.log('실패했습니다')
});
실패()
라는 함수를 실행하는 순간 실패판정을 내립니다.
그렇게 되면 catch()
내의 코드를 실행해줍니다.
실패의 경우 다른 내용을 실행해줄 수도 있고하니 그냥 콜백함수 디자인보다 훨씬 뭔가 직관적이고 유용합니다.
참고로 연산결과같은걸 then 안에서 활용하고 싶으면
성공();
함수 구멍안에 넣어주시면 됩니다.
let 프로미스 = new Promise(function(성공, 실패){
let 어려운연산 = 1 + 1;
성공(어려운연산);
});
프로미스.then(function(결과){
console.log('연산이 성공했습니다' + 결과)
}).catch(function(){
console.log('실패했습니다')
});
그럼 then
함수 안에서 파라미터의 형태로 그 결과를 사용하실 수 있다.
실제로 사용하는 예시를 하나 더 봅시다.
역시 콜백함수로 디자인해놓아도 될 것 같죠? 그럼 그렇게 하시면 됩니다.
하지만 저는 간지나게 then을 사용해보기 위해 Promise를 디자인해보겠습니다.
let 프로미스 = new Promise(function(성공, 실패){
setTimeout(function(){
성공();
}, 1000);
});
프로미스.then(function(){
console.log('1초 대기 성공했습니다')
}).catch(function(){
console.log('실패했습니다')
});
이러면 되겠죠?
아마 실패하는 경우는 없을 것 같아서 실패()
는 안썼습니다.
Ajax
, setTimeout
, AddEventListener
같은 것들 안에 콜백함수를 쓰기 싫은 경우, 콜백 함수 대신에 조금 더 코드를 예쁘게 디자인할 수있다.
let 프로미스 = new Promise( function(성공, 실패){
setTimeout( function() {
성공();
}, 1000);
});
프로미스 기계 발동
성공 or 실패에 따라 코드 실행
new Promise()
로 생성된 변수를 콘솔창에 출력해보시면 현재 상태를 알 수 있다. 성공/실패 판정 전에는 프로미스를 출력해보면,
<pending>
이라고 나온다.
=> 맨 앞에Promise
는 부모를 뜻하는 키워드
성공 후엔
<resolved>
or<fulfilled>
가 출력되고,then()
구문이 실행됐음을 알 수있다.
실패 후엔
<rejected>
가 출력되며,catch()
구문이 실행됐음을 알 수 있다.
Promise는 비동기적 실행과 전혀 상관이 없다.
그냥 코딩을 예쁘게 할 수 있는 일종의 디자인 패턴이다.
Promise
안에 10초 걸리는 어려운 연산을 시키면 10초동안 브라우저가 멈춘다.
10초 걸리는 연산을 해결될 때 까지 대기실(Web API
)에 제껴두고 그런거는 아니다.
즉, 10초동안 결과가 판정이 될 떄까지 then()
, catch()
어떤 것도 대기만 타고 있다.
jQuery.ajax()
$.ajax().done(function(){}).fail(...)
=> 이거 Promise랑 유사한 패턴 아닌가요??
fetch()
얘는 항상 Promise를 return한다.
즉, 성공/실패를 판정해서 fetch().then().catch()
를 실행할 수있다.
=> 날씨 API Sprint에서 해봤음!!