«   2024/09   »
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Archives
Today
Total
Recent Posts
Recent Comments
관리 메뉴

뉴히의 개발 로그

[TIL] 20230526 - Javascript : Promise(then/catch),async-await, setInterval(), setTimeout()함수. refactoring 본문

개발일지/TIL

[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