비동기 프로그래밍이란
자바스크립트는 싱글 스레드 언어이기 때문에 한 번에 하나의 작업만을 수행한다.
이를 동기적이라고 한다. 동기 방식은 간단하고 직관적이지만 장기 실행 함수의 경우 응답이 늦어져 전체적인 성능이 저하 된다.
동기적인 프로그래밍의 문제점
: 실행한 동기적 프로그래밍의 결과값이 나오기 전까지는 아무 작업도 시작할 수 없다.
그러면 이를 해결하기 위한 비동기 프로그래밍은 무엇을 해줄 수 있을까
- 함수를 호춤함으로써 장기적으로 실행되는 작업을 시작한다.
- 이 함수로 작업을 시작하고 즉시 복귀하여 다른 이벤트에 계속 응답할 수 있게 한다.
- 작업이 완료되면 결과를 알려준다.
즉, 비동기 함수 실행 시 응답이 오는 것에 상관없이 다른 작업을 이어나가 병렬적으로 작업을 처리할 수 있게 된다. 이는 총 코드 실행 시간을 감소할 수 있게 한다.
비동기 처리의 처리 원리
호출 스택과 이벤트 루프

- 비동기 함수의 콜백 함수가 이벤트 루프에 의해 callback queue에 담기고 다시 싱글 스레드인 call stack에 담겨서 콜백 함수가 실행되는 동작 원리
자바스크립트는 싱글 스레드 언어라고 했으면서 어떻게 병렬 처리가 가능한가요
- 자바 스크립트를 실행하는 Call Stack : 싱글 스레드
- 서버에게 리소스를 요청하거나 파일 입출력 혹은 타이머 대기 작업을 실행하는 Web APIs : 멀티 스레드
즉, 브라우저가 멀티 스레드이기 때문에 메인 자바스크립트의 싱글 스레드를 차단하지 않고 다른 스레드를 사용하여 Web API의 작업을 처리할 수 있기 때문에 비동기 처리가 가능한 것이다.
비동기 처리의 문제점
- 만일 그 다음 실행할 작업이 이전에 요청한 작업의 결과가 반드시 필요할 경우 문제가 생긴다.
- 서버로부터 데이터를 받을 때 비동기 함수의 결과가 동기적으로 실행되는 코드에 영향을 줄 때도 문제가 된다.
⇒ 작업의 순서를 맞추는 것이 필수 불가결일 경우에 문제가 생긴다.
이를 해결하기 위한 몇 가지 기법 중 가장 대표적인 것은 콜백 함수 기법이다.
콜백 함수
- 콜백 함수는 자바스크립트의 일급 객체 특성을 이용해 함수의 매개변수에 함수 자체를 넘겨 함수 내에서 매개변수 함수를 실행하는 기법을 말한다.
- 콜백 함수를 이용함으로써 간접적으로 작업 순서를 끼워 맞출 수 있다.
- 콜백 함수는 비동기 함수에서 작업 결과를 전달받아 처리하는데 사용되어 작업 순서를 맞출 수 있다.
⇒ 언뜻 문제가 해결되어 보이지만 콜백 함수는 비동기를 순차적으로 처리하기 위한 하나의 조치일 뿐 공식적인 해결 방식은 아니다.
Promise란 무엇인가
- Promise 객체는 이러한 한계점 극복을 위해 비동기 처리를 위한 전용 객체로서 탄생했다.
- Promise는 비동기 처리를 위한 전용 객체이다.
- Promise는 비동기 작업의 성공과 실패를 나눠 그 결과에 따른 코드를 실행할 수 있게 한다.
- const myPromise = new Promise((resolve, reject) => { setTimeout(() => { const success = true; if (success) { resolve("작업 성공!"); } else { reject("작업 실패."); } }, 2000); }); myPromise .then(result => { console.log(result); }) .catch(error => { console.error(error); });
Promise와 Callback
Promise와 Callback의 차이
- 에러 처리
- Callback은 단순히 비동기 작업의 결과를 처리하는 데 사용되지만
- Promise는 비동기 작업의 결과를 완료 / 실패로 나타내어 각 결과에 맞는 코드를 실행할 수 있다.
- 중첩 문제 해결
- Callback은 구조가 단순해 중첩이 쉬워 이른바 ~~‘콜백 지옥’~~을 발생시킬 수 있다.
- Promise는 중첩 문제에서 자유롭고 콜백보다 높은 가독성을 제공한다.
- Promise 체이닝을 통해 여러 비동기 작업을 간단하게 연결할 수 있으나
- 작업이 너무 복잡해질 경우 코드가 어려워질 수 있다.
Async, Await
- ES8에 해당하는 문법 async / await
- Callback처럼 Promise에도 Promise Hell이 존재한다. (주로 지나친 then 남용으로 일어난다.)
- 이를 해결하기 위한 async / await은 프로미스를 기반으로 하지만 마치 동기 코드처럼 쉽게 작성할 수 있게 해준다.
개념
- async 함수
- 함수 선언 앞에 async 키워드를 붙이면 해당 함수는 자동으로 Promise를 반환한다.
- async 함수 내부에서 reuturn 된 값은 자동으로 Promise.resolve()로 감싸져 반환된다.
- await 키워드
- await은 async 함수 내부에서만 사용 가능하며, Promise가 해결 될 때까지 함수 실행을 일시 정지한다.
- await 뒤에 오는 Promise가 해결되면 그 결과값을 반환하고 await은 거부 이유를 throw하여 예외를 발생시킬 수 있다.
예시 코드
async function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
const data = "데이터 로드 완료";
resolve(data);
}, 2000);
});
}
async function main() {
try {
const result = await fetchData();
console.log(result);
} catch (error) {
console.error("에러 발생:", error);
}
}
main();
- 비동기 코드를 동기식 코드처럼 작성할 수 있어 가독성이 좋다.
- try/catch 구문으로 오류를 직관적이고 일관되게 처리할 수 있다.
- 여러 개의 Promise를 더 간단하게 작성할 수 있다.
+) 웹 워커
- 웹 워커는 브라우저 환경에서 메인 스레드와 독립적으로 백그라운드에서 자바스크립트를 실행할 수 있게 하는 비동기 작업의 일환이다.
- 무거운 작업을 처리하면서도 UI의 변동 사항이 없기 때문에 사용자 경험을 개선할 수 있다.
예시 코드
// main.js (메인 스레드)
const worker = new Worker('worker.js');
worker.postMessage(1000000000);
worker.onmessage = function(event) {
console.log('결과:', event.data);
worker.terminate();
};
// worker.js (웹 워커)
self.onmessage = function(event) {
let result = 0;
for (let i = 0; i < event.data; i++) {
result += i;
}
self.postMessage(result);
};
장점
- UI 반응성 유지
- 성능 향상
- 독립적인 환경
- 웹 워커는 독립된 실행 환경에서 동작하므로 메인 스레드와 충돌 없이 작업을 수행할 수 있다.
출처
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Asynchronous/Introducing
https://developer.mozilla.org/ko/docs/Learn/JavaScript/Asynchronous
'TIL' 카테고리의 다른 글
자바스크립트의 this (0) | 2024.08.20 |
---|---|
자바스크립트의 타입 (0) | 2024.08.19 |
웹 프로토콜 (0) | 2024.08.15 |
함수형 프로그래밍 (Function Programming) (0) | 2024.08.14 |
http와 https의 통신 방법 차이 (0) | 2024.08.13 |