new Promise 키워드를 이용해서 생성.
promise는 인자로 함수를 받고 그 함수는 resolve function(보통 resolve라 명명)과 reject function(보통 reject라 명명) 두가지를 parameter를 가진다.
resolve나 reject 함수는 내가 직접 정의하는 것이 아니고 그냥 promise 내에서 promies가 달성(?), 혹은 실패 했다는 것을 나타내준다(제대로 이해한게 맞나 모르겠네...)
resolve() 의 ( ) 안에는 then에서 인자로 받을 것을 지정할 수 있고 이건 string, number, array, obj 뭐든 상관없다.
reject() 의 ( ) 안에는 catch 에서 사용할 인자를 지정한다.
const setTimer = (duration) => {
const promise = new Promise((resolve, reject) => {
//여기다 이제 무슨 일이 일어나야 할지 적음
setTimeout(() => {
resolve("Done!"); //resolve의 ( )안에 then에 넘겨줄 것을 입력.string이든 array이든 객체든 상관없음
}, duration);
});
return promise; // 이렇게 꼭 promise를 return 해줘야함
};
function trackUserHandler() {
navigator.geolocation.getCurrentPosition(
(posData) => {
setTimer(2000).then((data) => {
console.log(data, posData);
}); // promise obj 에 then 메서드를 쓸 수 있다.
},
(error) => {
console.log(error);
}
);
setTimer(1000).then(() => {
console.log("timer done!");
});
console.log("getting position...");
}
button.addEventListener("click", trackUserHandler);
then은 인자를 둘 받을수 있음. 첫번째는 promise가 resolve 되었을때 수행할 작업이고, 두번째 인자는 promise가 reject 되었을때 수행할 작업. 하지만 then의 두번째 인자로 에러 핸들링을 하는 것보다 catch를 쓰는 것이 더 읽기 편함
catch 블럭은 promise chain의 어디에든 추가할 수 있지만 어디에 추가하는 지에 따라 동작이 달라짐
.then() //여기서 에러가 나면
.then() //얘 건너 뛰고
.then() //얘도 건너뛰고
.catch() //얘가 그 에러를 잡아내서 이녀석의 코드가 실행된다.
.then() // 그리고 catch 이후의 then부터 다시 실행됨.
에러가 났을때 promise chain 전체를 멈추고 싶다면 catch를 마지막에 달아주면 되겠지.
catch블럭을 하나 이상 설정하는 것도 물론 가능하다.
async, await 은 then 과 catch를 생략할수 있게 해주는 구문이다
async await은 오직 함수에서만 쓸수 있고, 함수 선언문에선 function 키워드 앞에 async 키워드를 추가해서 이를 활성화 함.
function 키워드 없이 활성화된 함수(표현식)는 등호 옆에 async 를 붙여줌. 아래가 예시.
const setTimer = async () => { }
[follow up 10/29]
위에서 async 를 붙였을때 프로미스를 반환한다고 한것은 선택사항이 아니다! 즉 return 문을 따로 명시적으로 적어둔다고 해서 그 return문의 내용을 반환하게 만들 수는 없다. return문으로 뭘 반환하겠다고 적어놔도 무조건 반환되는 것은 promise다
async sayhi(){
return "hi! nice to meet ya"
}
같은게 있어서 마치 "hi! nice to meet ya" 스트링이 반환될것 같아 보여도 반환되는 것은 무조건 promise라는 의미이다.
async function trackUserHandler() {
const posData = await getPosition();
const timerData = await setTimer(2000);
console.log(timerData, posData);}
위 예시에서는 function 앞에 async를 붙이고, promise인 getPosition과 setTimer 앞에 await을 붙였다.
그리고 getPosition의 결과를 posData에 저장하고, setTimer의 결과를 timerData에 저장한 다음 그걸 콘솔에 찍은 것.
setTimer와 관련된 코드는 윗줄의 getPosition이 resolve될때까지 실행되지 않는다.
async function trackUserHandler() {
let posData;
let timerData;
try {
posData = await getPosition();
timerData = await setTimer(2000);
} catch (error) {
console.log(error);
}
console.log(timerData, posData);
두 promise가 둘다 resolve되면 catch 블록은 건너뛰고 그 다음줄이 실행되고, 위의 promies가 실행되면 그 아래 promise는 건너뛰고 catch 블록이 실행됨.
마지막 줄의 console.log는 error가 나건 resolve가 되건 상관없이 무조건 실행된다.
배열로 전달된 프로미스끼리 경주를 시킨다!
인자로 복수의 프로미스를 받아서 그중 가장 먼저 실행된 녀석의 반환된 결과를 다음 프로미스 체인으로 넘긴다
Promise.race([promise1(),promise2()]).then(data=>{console.log(data);})
이런식으로 적으면 promise1과 promise2중 더 빨리 완료된 것의 반환값이 then에 전달됨. 경주에서 이기지 못한 프로미스는 취소되는 것이 아니라 실행은 되지만 그 결과가 무시된다.
Promise.all([promise1(),promise2()]).then(promiseData=>{console.log(promiseData);})
이러면 promise1과 promise2 의 결과를 배열로 콘솔에 찍음.
Promise.all은 프로미스중 하나라도 실패하면 전체가 취소됨.
계속 찝찝한채로 애써 무시하고 있었던 부분중 하나인 promise를 공부해서 그래도 조금은 뭔지 감이 잡히게 되었다!
아직은 어렵게 느껴지는 부분들이 있지만 그래도 뭐가 어떻게 동작하는지는 대충 알것 같다.
완전히 이해하게 되려면 직접 코드를 쓸때 사용해봐야만 할것 같은데, 다음에 뭐 만들어 볼때 꼭 의도적으로 promise와 관련된 코드를 써보도록 하자!