안녕하세요, 코린이의 코딩 학습기 채니 입니다.
개인 포스팅용으로 내용에 오류 및 잘못된 정보가 있을 수 있습니다.
Promise
- 기존 callback 함수를 통한 비동기처리를 개선하기 위한 문법
- producer/consumer 코드를 연결
* producer (비동기처리가 포함된 코드)
* consumer (비동기 완료 후 실행할 코드)
속성
- status
- pending → fulfilled (이행) / rejected (거부)
- result
- undefined → value (이행 시) / error 객체 (거부 시)
Promise 기본
HTML 코드
<button id="btn1">basics</button>
Javascript 코드
- resolve : 이행(정상처리) 시 호출할 콜백함수 → then에서 전달
- reject : 거부 시 호출할 콜백함수 → catch에서 전달
btn1.onclick = () => {
const promise = new Promise((resolve, reject) => {
console.log("producing...");
});
console.log(promise);
};
state와 result가 'pending', 'undefined'인 것을 확인할 수 있습니다.
resolve가 실행 되면 fulfilled로 변경되며, reject가 실행되면 rejected 상태로 변경될 것입니다.
홀수가 나오면 resolve, 짝수가 나오면 reject로 상태 변화를 확인해보겠습니다.
btn1.onclick = () => {
const promise = new Promise((resolve, reject) => {
const num = Math.floor(Math.random()*2); // 0 또는 1
console.log("producing...", num);
try {
if(!num) throw new Error("오류 발생!");
resolve(num); // 이행 콜백 호출
} catch {
reject(e); // 거부 콜백 호출
}
});
console.log(promise);
};
홀수 (resolve) 시
state는 'fulfilled'로 변경되었으며, result는 value인 num(1)이 출력되었습니다.
짝수 (reject) 시
state는 'rejected'로 변경되었으며, result는 error 객체인 e가 출력 되었습니다.
여기까지가 producer 코드이고, 그렇다면 consumer(비동기 완료 후 처리할 코드) 코드는 어떻게 할까요?
resolve (이행) 시 호출할 콜백함수는 then에서 전달하고, reject (거부) 시 호출할 콜백함수는 catch에서 전달해줍니다.
btn1.onclick = () => {
const promise = new Promise((resolve, reject) => {
const num = Math.floor(Math.random()*2); // 0 또는 1
console.log("producing...");
try {
if(!num) throw new Error("오류 발생!");
resolve(num);
} catch {
reject(e);
}
});
console.log(promise);
promise
.then((value) => {
console.log('result = ', value);
})
.catch((err) => {
console.error('result = ', err);
})
};
resolve 시
reject 시
위처럼 처리되는 것을 확인할 수 있습니다.
<단순하게 정리>
resolve 시 호출할 콜백함수는 .then에서 넘겨준 함수 new Promise(resolve)에 들어가게 되고,
reject 시 호출할 콜백함수는 .catch에서 넘겨준 함수 new Promise(reject)에 들어가게 됩니다.
따라서 정상처리 시 .then에서 넘겨준 함수가 실행되고, 거부 시 .catch에서 넘겨준 함수가 실행됩니다.
또한, resolve/reject의 인자가 선언되어있으므로 인자를 받기 위해 .then/.catch에도 매개변수가 선언되어있는 것이죠.
Promise로 setTimeout 작성하기
HTML 코드
<button id="btn2">Promise - timeout</button>
Javascript 코드
btn2.onclick = () => {
getTimeoutPromise()
.then(() => {
console.log("1초가 지났습니다.");
})
};
const getTimeoutPromise = () => {
return new Promise((resolve) => {
setTimeout(() => {
resolve();
}, 1000)
});
};
getTimeoutPromise() 함수를 정의하였으며, 해당 리턴 값이 Promise 객체이기 때문에 함수 호출 후 then을 이용하여 정상처리 시 함수가 호출되도록 하였습니다.
마찬가지로 new Promise(resolve)에는 then의 함수가 대입되었으며, 1초 후 resolve()로 전달받은 then의 함수를 콜백함수로써 실행하게 되어 1초 후에 "1초가 지났습니다."가 출력됩니다.
그렇다면 getTimeoutPromise() 함수 호출 시 타이머 메세지와 시간을 넘겨받아보겠습니다.
btn2.onclick = () => {
getTimeoutPromise("안녕", 3000)
.then((value) => {
console.log(value);
})
};
const getTimeoutPromise = (msg, millis) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(msg);
}, millis)
});
};
getTimeoutPromise() 함수 호출 시, 타이머 메세지와 시간을 매개인자로 넘겨주게 되고 매개변수로 받아주었습니다.
resolve에 then 함수 (value) => console.log(value)가 대입(단순하게 생각해서), 해당 함수를 콜백함수로써 (resolve(msg))실행하였으므로 resolve의 매개인자 msg가 then (value)로 넘어갔으므로 값이 잘 출력 됩니다.
타이머가 실행되고 끝난 후 '실행 끝~'을 출력해보겠습니다.
방법1)
btn2.onclick = () => {
getTimeoutPromise("안녕", 3000)
.then((value) => {
console.log(value);
console.log('실행끝!');
})
};
const getTimeoutPromise = (msg, millis) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(msg);
}, millis)
});
};
방법2) then은 암묵적으로 Promise 객체를 만들어서 반환 (promise chain)
btn2.onclick = () => {
getTimeoutPromise("안녕", 3000)
.then((value) => {
console.log(value);
// console.log('실행끝!');
})
.then(() => console.log('실행끝!'));
};
const getTimeoutPromise = (msg, millis) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(msg);
}, millis)
});
};
then은 암묵적으로 Promise 객체를 만들어서 반환하므로 다시 then을 이용하여 값을 출력해줄 수 있습니다.
Promise Chain
① 암묵적 chain
- then의 resolve 콜백에서 리턴 값이 없다면, 암묵적으로 promise 객체 반환
- resolve 콜백에서 특정 값을 리턴한다면, 암묵적 promise 객체의 result 값으로 사용됨
② 명시적 chain
- then의 resolve 콜백에서 다시 Promise 객체를 반환 후 then 메소드로 chaining 가능
HTML 코드
<button id="btn3">Promise Chain - timeout</button>
Javascript 코드
btn3.onclick = () => {
getTimeoutPromise('안녕', 1000)
.then((value) => {
console.log(value);
return getTimeoutPromise('잘가', 1000)
})
.then((value) => console.log(value));
};
const getTimeoutPromise = (msg, millis) => {
return new Promise((resolve) => {
setTimeout(() => {
resolve(msg);
}, millis)
});
};
return 값이 Promise 객체이므로, 버튼을 누른 후 1초 뒤 '안녕'이 출력되고 1초 뒤 '잘가'가 출력되었습니다.
@실습 - 배경색 변경
- .bg-box 배경색을 1초 단위로 빨 → 초 → 노 → 파 → 핑으로 변경
HTML 코드
<button id="btn4">@실습문제 - 배경색변경</button>
<div class="bg-box"></div>
CSS 코드
<style>
.bg-box {
width: 100px;
height: 100px;
margin: 10px;
border: 1px solid black;
}
</style>
Javascript 코드
btn4.onclick = () => {
changeBgcolorPromise('red', 1000)
.then(() => changeBgcolorPromise('green', 1000))
.then(() => changeBgcolorPromise('yellow', 1000))
.then(() => changeBgcolorPromise('blue', 1000))
.then(() => changeBgcolorPromise('pink', 1000));
};
const changeBgcolorPromise = (color, millis) => {
const box = document.querySelector(".bg-box");
return new Promise((resolve) => {
setTimeout(() => {
box.style.backgroundColor = color;
resolve();
}, millis);
});
};
@실습 - 동적 스크립트 로딩
HTML 코드
<button id="btn5">@실습문제 - 동적 스크립트 로딩</button>
1.js
const bar = () => {
console.log('bar');
return '../js/2.js';
};
2.js
const car = () => {
console.log('car');
return "../js/3.js"
};
3.js
const dar = () => {
console.log("dar");
};
Javascript 코드
btn5.onclick = () => {
loadScriptPromise('../js/1.js')
.then(() => loadScriptPromise(bar()))
.then(() => loadScriptPromise(car()))
.then(() => dar())
};
const loadScriptPromise = (path) => {
return new Promise((resolve) => {
const script = document.createElement("script");
script.src = path;
script.onload = () => {
console.log(`${path} 로딩완료!`);
resolve();
};
document.head.append(script);
});
};
@실습 - 슬기로운 개발 생활
HTML 코드
<button id="btn6">슬기로운 개발생활</button>
Javascript 코드
<script>
const devActions = {
gotocafe : {
actionname : '카페로 출발합니다.',
duration : 1000,
next : 'arriveatcafe'
},
arriveatcafe : {
actionname : '카페에 도착했습니다.',
duration : 100,
next : 'startcoding'
},
startcoding : {
actionname : '코딩을 시작합니다.',
duration : 3000,
next : 'finishcoding'
},
finishcoding : {
actionname : '코딩을 마칩니다.',
duration : 0,
next : 'gotohome'
},
gotohome : {
actionname : '집으로 출발합니다.',
duration : 1000,
next : 'gethome'
},
gethome : {
actionname : '집에 도착했습니다.',
duration : 0
},
};
btn6.onclick = () => {
runDevAction('gotocafe')
.then((action) => runDevAction(action))
.then((action) => runDevAction(action))
.then((action) => runDevAction(action))
.then((action) => runDevAction(action))
.then((action) => runDevAction(action))
.catch((err) => console.error(err))
.finally(() => {
// 정상실행 혹은 에러 발생하든 반드시 실행됨
console.log('해가 지고, 하루가 끝났습니다.');
})
};
const runDevAction = (action) => {
const {actionname, duration, next} = devActions[action];
console.log(actionname);
return new Promise((resolve) => {
Math.random() * 100 > 90 && reject(new Error('친구에게 전화가 왔습니다.'));
setTimeout(() => {
resolve(next);
}, duration);
});
};
Promise chain - 값 반환
HTML 코드
<button id="btn7">Promise Chain - 값 반환</button>
Javascript 코드
btn7.onclick = () => {
new Promise((resolve) => {
resolve(1);
})
.then((value) => {
console.log(value);
return value * 2; // 암묵적 Promise 객체의 resolve(value)의 result(value)값이 됨
})
.then((value) => {
console.log(value);
return value * 2;
})
.then((value) => {
console.log(value);
return value * 2;
})
};
암묵적으로 생성된 Promise 객체의 resolve(value)는 result값이 되기 때문에 value * 2의 결과 값들이 출력된 것을 확인할 수 있습니다.
'JavaScript > JavaScript' 카테고리의 다른 글
Javascript) axios (랜덤 강아지/고양이 사진 추출) (0) | 2022.06.10 |
---|---|
fetch) fetch란? (Response.json(), 정보 추출하기) (0) | 2022.06.10 |
Javascript) 동기식 / 비동기식 - Timer API, DOM 관련 이벤트 처리, DOM 연속 (0) | 2022.06.02 |
Javascript) 정규표현식(4) - 수량자(*, +, ?, {}), Look Around, 비밀번호 유효성 검사 (0) | 2022.05.31 |
Javascript) 정규표현식(3) - [ ](숫자,영문,한글 범위), 단축문자(\d, \w, \s, \D, \W, \S), groung/or, escaping 처리 (0) | 2022.05.31 |