콜스택(Call Stack)
은 프로그래밍 언어에서 함수 호출을 관리하는 메모리 구조이다. 주로 자바스크립트, 파이썬, 자바 등 다양한 프로그래밍 언어에서 사용된다.
이름에서 알 수 있듯 Stack
구조이다.
Stack
구조는 한쪽 끝에서만 데이터를 넣고 뺄 수 있는 제한적으로 접근할 수 있는 LIFO(Last In First Out, 후입선출)
구조로 나중에 들어온 데이터를 먼저 뺀다.
function callStackEx(a, b){
return fn2(a,b) + fn2(b,a)
}
function fn2(a,b){ // a*b
a = a*b
return fn3(a,b)
}
function fn3(a,b){ // a+b
a = a+b
return a
}
callStackEx(2,3) // (2*3+3) + (3*2+2)
JavaScript
는 기본적으로 싱글 스레드(single-threaded)
이다.
싱글 스레드(single-threaded)
란 한 번에 하나의 작업만 처리할 수 있음을 의미 한다.
자바스크립트의 메인 스레드인 이벤트 루프가 싱글 스레드이기 때문에 싱글 스레드라고 부른다.
하지만 이벤트 루프만 독립적으로 실행되지는 않고 웹 브라우저나 NodeJS
같은 멀티 스레드 환경에서 실행된다.
즉, 자바스크립트 자체는 싱글스레드 이지만 자바스크립트 런타임은 싱글 스레드가 아니다.
📌 자바스크립트 런타임의 비동기(Asynchronous)
- 타이머 API (예: setTimeout, setInterval): 특정 시간 후에 코드를 실행.
- 네트워크 요청 (예: fetch, XMLHttpRequest): 서버와의 데이터 전송을 처리.
- DOM 이벤트 (예: addEventListener): 사용자 상호작용에 대한 응답을 처리.
setTimeout(function timeout() {
console.log("Click the button!");
}, 2000);
setTimeout(function timeout() {
console.log("Click the button!");
}, 2000);
console.log("Welcome to loupe.");
JavaScript
의 Promise
는 비동기 작업의 결과를 처리하기 위한 객체이다.
Promise
는 비동기 작업이 완료되었을 때 그 결과를 처리할 수 있는 방법을 제공하고, Promise
는 주로 비동기 작업이 성공했는지 실패했는지를 처리하는 데 사용된다.
Promise는 다음 세 가지 상태를 가질 수 있다:
Pending (대기 중)
: 초기 상태. 비동기 작업이 아직 진행중.Fulfilled (이행됨)
: 비동기 작업이 성공적으로 완료. 이 상태에서는 resolve
콜백이 호출.Rejected (거부됨)
: 비동기 작업이 실패했습니다. 이 상태에서는 reject
콜백이 호출.Promise
는 new Promise()
생성자를 사용하여 생성한다.
생성자 함수에는 두 개의 매개변수 resolve
와 reject
가 있다.
이 함수들은 비동기 작업이 완료되었을 때 호출된다.
const promiseEx = (url) => {
return new Promise((resolve, reject)=>{
const delay = Math.floor(Math.random() * 5500) + 500;
setTimeout(() => {
if(delay>=2000){
resolve(console.log("resolve"))
}else{
reject(console.log("reject"))
}
}, delay)
})
}
promiseEx("")
promiseEx("")
promiseEx("")
Promise 객체
는 then
과 catch
메서드를 사용하여 비동기 작업의 결과를 처리한다.
then(onFulfilled, onRejected)
: Promise가 이행된 경우 호출된다. 이 메서드는 두 개의 콜백 함수를 인수로 받는다. 첫 번째
는 작업이 성공적으로 완료되었을 때 호출되고, 두 번째
는 실패했을 때 호출된다.
catch(onRejected)
: Promise가 거부된 경우 호출된다. 이 메서드는 작업이 실패했을 때만 호출된다.
const promiseEx = (url) => {
return new Promise((resolve, reject)=>{
const delay = Math.floor(Math.random() * 5500) + 500;
setTimeout(() => {
if(delay>=2000){
resolve("resolve")
}else{
reject("reject")
}
}, delay)
})
}
const ex1 = promiseEx("");
ex1.then(result => {
console.log(result); // "then resolve"
})
.catch(error => {
console.log(error); // "catch reject" (실패 시)
});
async/await
는 promise
의 코드의 가독성이 떨어지고 에러가 어디서 일어났는지 보기 어려워진다는 단점을 보완해준다.
async 함수
는 자동으로 Promise
를 반환하도록 해준다.
함수 앞에 async
를 붙이면 해당 함수는 자동으로 비동기 함수가 된다.
async function handleSubmit() {
...
return exampleAsync
// return Promise.resolve(exampleAsync) // 위와 같은 결과
}
await
는 async 함수 내에서만 사용될 수 있는 표현식으로, Promise의 결과를 기다리는 데 사용된다.
await
는 해당 Promise의 상태가 바뀔 때까지 코드가 기다린다. Promise가 성공 상태 또는 실패 상태로 바뀌기 전까지는 다음 연산을 시작하지 않는 것이다.
사실상 await
는 then()
과 같은 역할을 하는데, 콜백 함수를 등록할 필요가 없기 때문에 더 편리하다
// 비동기 작업을 모사하는 함수
function fetchData() {
return new Promise((resolve) => {
setTimeout(() => {
resolve("Data fetched successfully");
}, 1000); // 1초 후에 데이터 반환
});
}
// async 함수 정의
async function getData() {
console.log("Fetching data...");
// 비동기 함수에서 await 사용
let data = await fetchData();
console.log(data); // "Data fetched successfully"
}
// async 함수 호출
getData();