뉴히의 개발 로그
[TIL] 20230526 - Javascript : Promise(then/catch),async-await, setInterval(), setTimeout()함수. refactoring 본문
[TIL] 20230526 - Javascript : Promise(then/catch),async-await, setInterval(), setTimeout()함수. refactoring
뉴히 2023. 5. 26. 20:50
Promise
Promise는 프로미스가 생성된 시점에는 알려지지 않았을 수도 있는 값을 위한 대리자로, 비동기 연산이 종료된 이후에 결과 값과 실패 사유를 처리하기 위한 처리기를 연결할 수 있다. 프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있다. 다만 최종 결과를 반환하는 것이 아니고, 미래의 어떤 시점에 결과를 제공하겠다는 '약속'(프로미스)을 반환한다.
- Promise는 비동기 처리에 대해, 처리가 끝나면 알려달라는 ‘약속’
- new 연산자로 호출한 Promise의 인자로 넘어가는 콜백은 바로 실행
- 그 내부의 resolve(또는 reject) 함수를 호출하는 구문이 있을 경우 resolve(또는 reject) 둘 중 하나가 실행되기 전까지는 다음(then), 오류(catch)로 넘어가지 않음
- 따라서, 비동기작업이 완료될 때 비로소 resolve, reject 호출
- 매개변수resolve 와 reject 는 함수로서 호출되면 promise 를 이행하거나 거부합니다. 이 둘을 이용하여 비동기 작업이 모두 끝나면 resolve 를 호출해 이행하고, 중간에 오류가 생기면 reject 를 이용해 거부
- 우선 Promise 는 매개변수로 executor 를 받는다. executor 는 resolve 와 reject 인수를 전달할 실행함수
// new Promise(콜백함수) -> 바로 실행
new Promise(function(resolve){
setTimeout(function(){
let name = "에스프레소";
console.log(name);
resolve(name); // 리졸브로 인자를 넘겨줌
},500)
}).then(function(prevName){// 리졸브에 있던 인자를 넘겨받음
return new Promise(function(resolve){// 이안에서도 새롭게 Promise를 만들어요
setTimeout(function(){
let name = prevName + ", 아메리카노";
console.log(name);
resolve(name);
},500)
})
}).then(function(prevName){
return new Promise(function(resolve){
setTimeout(function(){
let name = prevName + ", 카페모카";
console.log(name);
resolve(name);
},500)
})
}).then(function(prevName){
return new Promise(function(resolve){
setTimeout(function(){
var name = prevName + ", 카페라떼";
console.log(name);
resolve(name);
},500)
})
});
위 코드를 refactoring 한 코드 : 반복되는 함수코드는 변수를 사용해서 코드를 줄일 수 있다.
let addCoffee = function(name){
return function(prevName){
return new Promise(function(resolve){
setTimeout(function(){
// var name = prevName + ", " + name;
var newName = prevName ? `${prevName}, ${name}` : name; // 빽틱을쓴 경우
console.log(newName);
resolve(newName);
},500)
})
}
}
addCoffee("에스프레소")()
.then(addCoffee("아메리카노"))
.then(addCoffee("카페모카"))
.then(addCoffee("카페라떼"));
Promise 상태
- 대기(pending): 이행하지도, 거부하지도 않은 초기 상태.
- 이행(fulfilled): 연산이 성공적으로 완료됨.
- 거부(rejected): 연산이 실패함.
참고 https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
참고 https://ssungkang.tistory.com/entry/ES6-Promises-then-catch-all-race-finally
then과 catch
then 메서드는 Promise를 리턴하기 때문에, 이어지는 then 호출들을 손쉽게 연결할 수 있다
const p2 = new Promise((resolve, reject) => {
resolve(1);
});
p2.then((value) => {
console.log(value); // 1
return value + 1;
}).then((value) => {
console.log(value, "- A synchronous value works"); // 2 - A synchronous value works
});
p2.then((value) => {
console.log(value); // 1
});
try...catch 문은 실행할 코드블럭을 표시하고 예외(exception)가 발생(throw)할 경우의 응답을 지정
try {
nonExistentFunction();
} catch (error) {
console.error(error);
// Expected output: ReferenceError: nonExistentFunction is not defined
// (Note: the exact output may be browser-dependent)
}
async와 await
async와 await라는 특별한 문법을 사용하면 Promise를 좀 더 편하게 사용할 수 있다.
// coffeeMaker 함수에서 호출할 함수, 'addCoffee'를 선언
// Promise를 반환
let addCoffee = function(name){
return new Promise(function(resolve){
setTimeout(function(){
resolve(name);
},500)
})
}
// ***
var coffeeMaker = async function () { // async는 function 앞에 붙는다.
// var coffeeMaker = async () => { 화살표 함수의 경우
var coffeeList = '';
var _addCoffee = async function (name) {
coffeeList += (coffeeList ? ', ' : '') + await addCoffee(name);
};
// promise를 반환하는 함수인 경우, await를 만나면 무조건 끝날 때 까지 기다린다.
// await _addCoffee('에스프레소')이 로직이 실행되는데 100초가 걸렸다...면
await _addCoffee('에스프레소');
// 아래 console.log는 100초 뒤 실행
console.log(coffeeList);
await _addCoffee('아메리카노');
console.log(coffeeList);
await _addCoffee('카페모카');
console.log(coffeeList);
await _addCoffee('카페라떼');
console.log(coffeeList);
};
coffeeMaker();
- await 키워드를 만나면 promise가 처리될 때까지 기다린 이후 결과가 반환된다
- function 앞에 async를 붙이면 해당 함수는 항상 promise를 반환하고, promise가 아닌 것은 promise로 감싸 반환
- await은 async 함수 안에서만 동작 한다
참고 https://ko.javascript.info/async-await
setInterval() 함수
웹페이지의 특정부분을 주기적으로 업데이트 해줘야하거나, 어떤 API로 부터 변경된 데이터를 주기적으로 받아와야 하는 경우 사용 할 수 있따.
setInterval() 함수는 어떤 코드를 일정한 시간 간격을 두고 반복해서 실행 할 때 사용.
첫번째 인자로 실행할 코드를 담고 있는 함수를 받고, 두번째 인자로 반복 주기를 밀리초(ms) 단위로 받는다.
세번째 인자부터는 추가 인수들은 받을 수 있다.
setInterval(code)
setInterval(code, delay)
setInterval(func)
setInterval(func, delay)
setInterval(func, delay, arg0)
setInterval(func, delay, arg0, arg1)
setInterval(func, delay, arg0, arg1, /* … ,*/ argN)
사용 방법 예시
현재시간을 2초마다 출력
setInterval(() => console.log(new Date()), 2000);
// 결과
2023-05-26T02:30:17.787Z
2023-05-26T02:30:19.791Z
2023-05-26T02:30:21.795Z
2023-05-26T02:30:23.805Z
2023-05-26T02:30:25.813Z
2023-05-26T02:30:27.814Z
숫자를 변수에 저장하고 2초마다 1씩 증가
let count = 0;
setInterval(() => console.log(++count), 2000);
// 결과
1
2
3
4
5
6
7
8
9
10
clearInterval() -> 실행종료
const intervalID = setInterval(myCallback, 500, 'Parameter 1', 'Parameter 2');
function myCallback(a, b){
console.log(a);
console.log(b);
}
clearInterval(intervalID);
setInterval() 함수는 인터벌 아이디(Interval ID)라고 불리는 숫자를 반환하는데요. 인터벌 아이디는 setInterval() 함수를 호출할 때 마다 내부적으로 생성되는 타이머 객체를 가리키고 있습니다. 이 값을 인자로 clearInterval() 함수를 호출하면 코드가 주기적으로 실행되는 것을 중단시킬 수 있다.
setTimeout() 함수
어떤 코드를 바로 실행하지 않고 일정 시간을 기다린 후 실행 하는경우 자바스크립트의 setTimeout()함수를 사용.
setTimeout() 함수는 첫번째 인자로 실행할코드를 담고있는 함수, 두번째 인자로 지연시간을 밀리초(ms) 단위로 받는다.
var timeoutID = setTimeout(function[, delay, arg1, arg2, ...]);
var timeoutID = setTimeout(function[, delay]);
var timeoutID = setTimeout(code[, delay]);
예시코드
setTimeout(() => console.log("2초 후에 실행됨"), 2000);
세번째 인자부터는 가변인자를 받는다.
첫번째 인자로 넘어온 함수가 인자를 받는 경우, 이 함수에 넘길 인자를 명시해주기 위해서 사용
예시코드
function add(x, y) {
console.log(x + y);
}
setTimeout(add, 2000, 3, 4);
// 결과
7
setTimeout() 함수는 타임아웃 아이디(Timeout ID)라고 불리는 숫자를 반환하는데요. 타임아웃 아이디는 setTimeout() 함수를 호출할 때 마다 내부적으로 생성되는 타이머 객체를 가리키고 있습니다. 이 값을 인자로 clearTimeout() 함수를 호출하면 기다렸다가 실행될 코드를 취소할 수 있습니다.
const timeoutId = setTimeout(() => console.log("5초 후에 실행됨"), 5000);
clearTimeout(timeoutId);
// 아무것도 실행 안됨
setTimeout() 함수와 setInterval() 함수는 대동소이하다.
setTimeout() 함수와 setInterval() 함수를 사용한 후에는 반드시 clearTimeout() 함수와 clearInterval() 함수를 사용해서 타이머를 청소해주는 습관을 들여라. 특히, SPA(Single Page Application)을 개발할 때는 이 부분이 메모리 누수(memory leak)로 이어질 수 있기 때문에 각별히 주의가 필요하다고한다!
참고 : https://www.daleseo.com/js-timer/
참고 : https://developer.mozilla.org/ko/docs/Web/API/setTimeout