# 비동기 프로그래밍 (Asynchronous Programming) 자바스크립트는 단일 스레드 기반의 언어로, 한 번에 하나의 작업만 실행할 수 있는 싱글 스레드 모델을 따릅니다. 하지만 비동기 프로그래밍을 통해 여러 작업을 동시에 처리할 수 있는 것처럼 보이게 하고, 효율적인 프로그램을 만들 수 있습니다. 비동기 프로그래밍은 **시간이 오래 걸리는 작업(예: 파일 읽기, 데이터베이스 요청, API 호출)**을 실행하는 동안 다른 작업을 멈추지 않고 동시에 처리할 수 있도록 합니다. 자바스크립트의 **이벤트 루프(Event Loop)**와 **콜백 큐(Callback Queue)**는 비동기 작업을 가능하게 하는 핵심 메커니즘입니다. ## 이벤트 루프(Event Loop) 이벤트 루프는 비동기 작업이 완료되었을 때 콜백 함수를 호출하여 실행할 수 있도록 관리합니다. * 콜 스택(Call Stack): 실행할 함수가 저장되는 공간. * 콜백 큐(Callback Queue): 비동기 작업이 완료된 후 실행 대기 중인 콜백 함수들이 대기하는 공간. 이벤트 루프는 **콜 스택이 비어 있을 때** 콜백 큐에서 작업을 가져와 실행합니다. ## 비동기 처리 방식 비교 * 콜백 함수 - 간단한 비동기 작업에 적합 - 콜백 지옥 발생 가능 * Promise - 가독성이 좋고 에러 처리가 간편 - 체인 길어질 경우 가독성 저하 * async/await - 동기식 코드처럼 작성 가능, 가독성 뛰어남 - 여러 개의 비동기 처리 병렬 실행은 불편 ## 콜백 함수 (Callback Function) 콜백 함수는 함수의 인자로 전달되어 특정 작업이 완료된 후 실행됩니다. ```javascript console.log("시작"); setTimeout(() => { console.log("3초 후 실행"); }, 3000); console.log("끝"); // 시작 // 끝 // 3초 후 실행 ``` ### 콜백 지옥 (Callback Hell) 콜백 함수가 중첩되면서 코드가 복잡하고 읽기 어려워지는 문제를 콜백 지옥이라고 합니다. ```javascript setTimeout(() => { console.log("1단계"); setTimeout(() => { console.log("2단계"); setTimeout(() => { console.log("3단계"); }, 1000); }, 1000); }, 1000); ``` ## 프로미스 (Promise) ES6에서 도입된 Promise는 비동기 작업을 보다 깔끔하게 처리할 수 있는 방법입니다. Promise는 대기(Pending) → 성공(Fulfilled) → 실패(Rejected) 상태를 가집니다. ```javascript const myPromise = new Promise((resolve, reject) => { const success = true; if (success) { resolve("작업 성공!"); } else { reject("작업 실패!"); } }); myPromise .then(result => { console.log(result); // 출력: 작업 성공! }) .catch(error => { console.error(error); }); ``` * resolve: 비동기 작업이 성공적으로 완료되었을 때 호출되는 함수입니다. * reject: 비동기 작업이 실패했을 때 호출되는 함수입니다. * then: Promise가 성공적으로 완료되었을 때 실행될 함수를 전달합니다. * catch: Promise가 실패했을 때 실행될 함수를 전달합니다. * Promise.resolve: 이미 완료된 값을 가지는 Promise를 생성합니다. * Promise.reject: 실패한 Promise를 생성합니다. ### Promise 체이닝 then 메서드는 새로운 Promise를 반환하므로, 여러 개의 then 메서드를 연결하여 비동기 작업을 순차적으로 실행할 수 있습니다. ```javascript promise .then(result => { return result + ' 추가 작업'; }) .then(result => { console.log(result); // '작업 완료! 추가 작업' 출력 }) .catch(error => { console.error(error); }); ``` ### 병렬 처리 비동기 작업을 병렬로 실행하려면 **Promise.all**이나 **Promise.allSettled**을 사용할 수 있습니다. ```javascript const promise1 = new Promise(resolve => setTimeout(() => resolve("1초 후 완료"), 1000)); const promise2 = new Promise(resolve => setTimeout(() => resolve("2초 후 완료"), 2000)); Promise.all([promise1, promise2]).then(results => { console.log(results); // 출력: ["1초 후 완료", "2초 후 완료"] }); ``` * Promise.all: 여러 개의 Promise를 동시에 실행하고, 모든 Promise가 완료되었을 때 결과를 반환합니다. * Promise.race: 여러 개의 Promise 중 가장 먼저 완료된 Promise의 결과를 반환합니다. ## async와 await Promise를 더욱 간결하게 사용할 수 있는 방법입니다. async와 await는 비동기 작업을 동기적인 코드처럼 읽기 쉽게 작성할 수 있도록 도와줍니다. ```javascript function fetchData() { return new Promise(resolve => { setTimeout(() => { resolve("데이터 로드 완료!"); }, 2000); }); } async function getData() { console.log("데이터 요청 중..."); const result = await fetchData(); console.log(result); // 출력: 데이터 로드 완료! } getData(); ``` * async: 함수가 비동기 함수임을 나타냅니다. * await: Promise가 완료될 때까지 기다리고, 그 결과를 반환합니다.