동기, 비동기
요청 작업을 순서를 지켜서 순차적으로 처리를 하는지 여부에 따라 동기와 비동기로 나눌 수 있다. 동기 처리 방식은 직렬적으로 작업을 수행하고 비동식 처리 방식은 병렬적으로 작업을 수행한다. 비동식 처리 방식에는 네트워크 요청 작업이나 이미지 의 작업들이 해당된다. 비동기 작업을 처리하기 위한 패턴으로 콜백 함수를 이용해서 동시에 작업을 처리할 수 있도록 해준다.
자바스크립트는 싱글 쓰레드로 작동하는 언어이다.
하나의 쓰레드 = 하나의 콜 스택 = 한 번에 하나의 작업 수행
즉, 쓰레드가 하나만 있기 때문에 한 번에 하나의 작업만 수행할 수 있다. 그러나, 비동기 작업 처리를 가능하게 해주는 것이 있는데 바로 이벤트 루프이다.
이벤트 루프
기본적으로 자바스크립트가 실행되는 과정에 메모리 할당이 이루어지는 메모리 힙(Memory Heap)과 Execution Context가 쌓이는 콜 스택(Call Stack)이 있다. 코드가 실행될 때마다 콜 스택에 하나씩 쌓이지만 일부 코드는 콜 스택에 쌓이지 않는다. setTimeout 이라는 함수가 대표적인데, 이 콜백 함수는 V8과 같은 자바스크립트 엔진에 내장되어 있지 않고 웹 브라우저에서 제공하는 Wep API들이다. Wep API들이 있기에 동시에 작업 처리가 가능해진다.
여기서 이벤트 루프는 콜 스택과 콜백 큐를 지속적으로 감시하는 역할을 하며 만약 콜 스택이 비어있고 콜백 큐에는 함수나 값 등이 있다면 콜 스택으로 옮기는 작업을 한다.
이벤트 루프는 비동기 작업을 처리하기 위한 동작 방식으로, 자바스크립트 엔진과 자바스크립트가 구동되는 환경이 서로 상호 연동하기 위한 장치이다. HTTP 요청, 타이머 작업, 이벤트 핸들러 등의 비동기 작업은 이벤트 루프로 처리가 된다.
프로미스
콜백 함수가 반복되다보면 콜백 지옥에 빠질 수 있다. 콜백 패턴이 가진 단점을 보완한 비동기 처리 패턴이자 객체가 Promise다. Promise에는 3가지의 상태가 있고 pending(대기상태), fulfilled(이행상태), rejected(거부상태)가 있다.
프로미스가 생성된 직후의 기본 상태는 pending 상태이고 비동기 처리가 성공적으로 수행되면 fulfilled 상태, 비동기 처리가 실패하면 rejected 상태로 변경된다. fulfilled 상태에서는 resolve 함수를 호출하고 rejected 상태에서는 reject 함수를 호출한다.
const promise = new Promise(() => {
setTimeout(() => {
const txt = prompt("비밀번호를 입력하세요");
if (txt === 1234) {
resolve('성공');
} else {
reject('에러');
}
}, 1000);
});
프로미스는 생성과 동시에 실행이 되며, 결과값을 출력하기 위해서는 then, catch, finally와 같은 프로미스의 후속 처리 메서드를 사용해야 한다. then, catch, finally 메서드는 프로미스를 반환하기 때문에 연속적으로 호출할 수 있다. 이를 프로미스 체이닝이라고 한다. 프로미스 객체로 같은 객체에 메소드를 연속적으로 호출하는 메소드 체이닝을 한다고 해서 프로미스 체이닝이라 한다.
프로미스의 상태가 변화하면 then, catch에 인수로 전달한 콜백 함수들이 호출된다. then은 두 개의 콜백 함수를 인자로 받는다. 하나는 프로미스가 fulfilled 상태가 되었을 때, 다른 하나는 rejected 상태가 되었을 때를 위한 콜백 함수이다. catch 메서드는 한 개의 콜백 함수를 인자로 받고, 프로미스가 rejected 상태인 경우에 출력되며 then 메서드를 호출한 이후에 발생한 모든 에러를 캐치한다. finally 메서드는 비동기 작업이 resolve나 reject 되어도 항상 호출된다. 한 개의 콜백 함수를 인자로 받지만 콜백 함수에서는 어떠한 인자도 받지 않는다.
promise
.then(result => {
console.log(result);
})
.catch(err => {
console.log(err);
})
.finally(() => {
console.log("끝");
});
프로미스 정적 메서드
- Promise.resolve(): fulfilled(이행) 상태의 프로미스 객체 생성
- Promise.reject(): rejected(거부) 상태의 프로미스 객체 생성
- Promise.all(): 여러 개의 프로미스를 동시에 실행. 모든 결과가 끝나면 한 번에 출력. 순서가 보장된다는 특징이 있음. 하나라도 거부 된다면 전체 프로미스가 거부됨. 에러가 여러개라면 첫 번째로 만나는 에러를 출력
- Promise.allSettled(): 여러 개의 프로미스 동시에 실행. 모든 프로미스가 이행되거나 거부될 때까지 기다리고 거부 되어도 전부 출력 & 거부 이유도 명시
- Promise.any(): 여러 개의 프로미스 동시에 실행. 하나라도 이행 되면 해당된 프로미스의 값만 바로 반환. 모든 프로미스가 거부될 때에만 전체 프로미스가 거부
- Promise.race(): 가장 빨리 처리되는 프로미스의 값을 반환. 넣어주는 배열의 순서에 따라 출력에도 차이 있음.
참고자료
'IT Study > JavaScript' 카테고리의 다른 글
[JS] 비동기 처리 패턴 async, await (0) | 2023.09.06 |
---|---|
[JS] setTimeout의 clearTimeout, 디바운싱, 쓰로틀링 (0) | 2023.09.06 |
[JS] 제곱 리스트를 찾는 방법(filter, map, reduce, every) (0) | 2023.09.01 |
[JS] 🐰기록하고 보기 위한 '놓치기 쉬운 부분들' (DOM요소, setInterval 함수, target, every(), substring)_엘리스3주차 (0) | 2023.09.01 |
[JS] 유사배열객체를 배열로 변환(Array.from, slice.call, map.call, 전개구문, 얕은복사) (0) | 2023.09.01 |