비동기 질문 리스트
해당하는 질문들을 대답할 수 있도록, 본인이 공부한 흐름에 맞게 정리하여 올려주세요.
동기와 비동기란 무엇인가요?
프로미스란 무엇이고 어떻게 사용되나요?
콜백 헬을 해결할 수 있는 방법은 무엇이 있을까요?
프로미스와 async/await의 차이점은 무엇일까요?
인수 비동기
1. 동기와 비동기, 블로킹과 논블로킹
[동기와 비동기]
- 동기와 비동기는, 여러 작업들이 동시에 실행될 수 있는가를 기준으로 분류해볼 수 있습니다.
정의
동기(Synchronous)는 선행 작업의 종료시점과, 후행 작업의 시작 시점이 일치하는 것을 말하며, 네트워크 관점에서는, 요청을 보낸 후, 응답(결과)를 받아야지만, 다음 동작을 진행할 수 있는 것을 말합니다.장단점
설계가 간단하고, 직관적인 장점이 있는 반면, 하나의 작업을 요청하고, 처리하는 과정에서 다른 작업을 진행하지 못하므로, 시스템의 전체적인 비효율이 발생할 수 있습니다.정의
비동기(Asynchronouse)는 선행작업의 종료 시점과, 후행 작업의 시작 시점이 일치하지 않는 것을 말하며, 이에 따라 하나의 요청이 응답(결과)를 받아 끝나기 전에, 다른 여러 요청이 동시적으로 발생할 수 있는 것을 말합니다.장단점
시스템 자원을 효율적으로 사용할 수 있는 장점이 있는 반면, 여러 작업이 동시에 처리되어, 해당 작업들의 순서성을 보장하기 어렵고 이에 따른 후속 처리 작업의 설계가 복잡할 수 있다는 단점을 가지고 있다.
[블로킹과 논블로킹]
- 블로킹과 논블로킹은 ‘하나의 동작의 속도와 상태’ 에 따라 분류해볼 수 있습니다.
- 블로킹은 정확한 정의는 존재하지 않지만, 대체로 느리게 동작되어, 스택에 오래동안 자리잡아, 다른 동작을 막고 있는 상태, 즉 “CallStack이 멈추어 있는 상태” 를 블로킹 상태라고 할 수 있습니다.
[비동기와 논블로킹]
동기적 처리의 문제점 때문에, 브라우저는 AJAX 요청등을 비동기적으로 실행한다.
- 자바스크립트의 코드 자체는 동기적으로 작동한다.
- 웹 브라우저의 Web APIs 는 비동기적으로 처리한다.
- Web APIs의 setTimeout, DOM, AJAX 요청등이 대표적인 사례
- 자바스크립트 자체는 비동기적 요청을 처리할 수 없기 때문에, 자바스크립트 런타임이 지원하는 API를 통해 비동기 요청을 처리한다.
- 이 비동기 처리는 웹브라우저의 이벤트 루프와 콜백 큐를 통해 가능하다.
- 비동기 콜백 방식을 통해, 싱글 스레드 프로그래밍 언어에서 발생하는 블로킹을 해결할 수 있다.
- 싱글스레드는 스레드가 하나이기 때문에, 블로킹 상태에 직면할 확률이 높다.
- *스레드가 여러개라면, 동기적 요청이 여러개 있어도 논블로킹 상태일 수 있다.
- 비동기 콜백 방식으로, 당장 콜스택에 함수를 바로 실행하는 것이 아니라, 다른 곳에 쌓아 두어 동시에 요청을 처리하도록 하고(Web APIs에 위임하여, 비동기로 논블로킹 상태를 만듦), 요청이 완료된 순서대로 처리하도록 한다.
- “⇒ 이벤트 루프”
2. 이벤트 루프
이벤트루프는 “자바스크립트 런타임(브라우저)”에서 비동기 콜백을 만들어 처리한다.
- ‘Web APIs’ 에서 실행되는 비동기 동작의 결과인 콜백함수들은 ‘콜백 큐(callback Queue)’에 쌓인다.
- 이벤트 루프는 ‘콜 스택’ 과 ‘콜백 큐'를 주시한다.
- 콜스택이 비어 있다면, 큐의 첫번째 콜백을 스택에 쌓아 실행시킨다.

3. 콜백함수와 비동기 처리
[1. 콜백함수란?]
- 콜백(callback)이란 다른 함수(A)의 전달인자(argument)로 넘겨주는 함수(B)를 말한다.
- 넘겨주는 함수(B)의 제어권은 전달받은 함수(A)가 가지게 된다.
function A (someArg1, callback){ ... if(someArg1 === true){ callback(); } } function B(){ console.log('this is callback 함수 실행'); } A(true, B) // 'this is callback 함수 실행'
[2. 콜백함수 예시]
- iterator
[1,2,3].map(
(el,idx) ⇒ console.log(`${idx}번째 요소는 ${el}` 이다.)
)
- 고차함수는 callback함수를 받아, 순환하며 해당 callback을 실행하도록 하는 함수이다.
- eventHandler
$(’#app’).addEventListener(’click’, (e) ⇒ { console.log(’click 발생할 때 실행되는 콜백함수 이다. ’) )
[3. 동기적 콜백과 비동기적 콜백의 차이]
- 동기적 콜백
- 하나의 작업이 모두 종료된 이후에 새로운 작업을 실행하는 방식 (
블로킹 발생
)
// 동기적으로 3초 마다 배열의 수가 출력된다. (블로킹을 느낄 수 있다.) [1, 2, 3].forEach((num) => { // 콘솔 한번 찍히려면 매번 3초씩 걸린다. // 이 함수의 콜백 함수는 동기적으로 호출된다. imCallbackFn(() => console.log(num), 3000); }); function imCallbackFn(callback) { let start = Date.now(); let now = start; while( now - start < 3000 ) { now = Date.now(); } callback(); } // 콘솔 출력까지 총 수행 시간 3 * 3 = 9초 // 의도적으로 타이머의 기능이 필요하다면 동기적 콜백 호출이 필요할 수도 있다.
- 비동기적 콜백
- 새로운 요청과 이전 요청에 대한 처리를 동시에 진행하는 방식
// 비동기적으로 3초 이후 배열의 수가 출력된다. (논 블로킹을 느낄 수 있다.) [1, 2, 3].forEach((num) => { // 자바스크립트 런타임의 'Web API'인 'setTimeout' 함수를 사용함으로써 // 3초 이후 콘솔이 모두 출력된다. // 이 함수의 콜백 함수는 비동기적으로 호출된다. setTimeout(() => console.log(num), 3000); }); // 콘솔 출력까지 총 수행 시간 = 3초 // 블로킹을 해결하고 속도를 개선하려면 비동기적 콜백 호출을 이용한다.
- 이어지는 질문 > 자바스크립트에서 동기/비동기 작업은 어떻게 처리되는가 (이벤트루프, 싱글스레드)
4. 비동기 처리와 비동기 제어
[비동기 처리, 비동기 제어란]
- 자바스크립트의 비동기 처리는 브라우저의 WebAPIs의 비동기함수들의 도움을 받아 진행한다.
- 브라우저의 WebAPIs에서 사용가능한 비동기 함수는 아래와 같다.
- DOM의 이벤트 핸들러 함수
- 타이머 관련 함수 (setTimeout, 애니메이션API)
- 서버에 대한 요청 (fetch, AJAX)
- 비동기 함수들은, *결과를 쉽게 예상할 수 없다는 치명적 단점을 가지고 있다.
- 각각의 task의 종료시점을 알 수 없기 때문에, 콜백함수의 순서를 제어할 필요가 있다.
- 비동기 처리란, 비동기 함수가 가진 콜백함수들의 순서를 제어하는 것을 말한다.
- 자바스크립트의 비동기 처리란 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미합니다. (ref. josha)
5. 콜백 / 프로미스 / async-await
5.1 콜백을 통한 비동기 제어
function fn() { setTimeout(() => { console.log('하나'); setTimeout(() => { console.log('둘'); setTimeout(() => { console.log('셋'); }, 0); }, 0); }, 0); } fn(); // 결과 순서 => '하나', '둘', '셋'
- 비동기 함수 내의 콜백함수를 통해, 특정 동작을 실행시킬 수 있다.
- 이 콜백함수안에 또 다른 비동기함수를 호출한다면, 여러 작업을 순차적으로 실행시킬 수 있다.
[문제점]
- 콜백 지옥 (순차성 보장하지못함)
- 콜백함수의 순서를 확정하기 위해, 콜백함수안에 반복적으로 비동기함수를 호출하는 작업의 결과로 들여쓰기가 깊어지며, 가독성을 헤치는 현상을 말한다.
- 가독성, 직관적 이해, 코드 수정을 어렵게 한다.
- 에러처리가 어려움
- setTimeout 함수는 콜백함수를 WebAPIs에 넘긴 직후, 콜스택에서 제거되기 때문이다.
- 따라서 1초 후 Error가 발생했을 때는, setTimeout함수는 콜스택에 존재하지 않고, 콜백함수를 호출한 함수가 setTimeout 함수가 아닌 것을 뜻한다. 따라서 호출자 방향으로 전파되는 에러(exeption)에 catch 되지 않는 것이다.
try { setTimeout(() => { throw new Error('Error!'); }, 1000); } catch (e) { console.log('에러를 캐치하지 못한다..'); console.log(e); }
- 제어의 역전 문제
- 제어의 역전은, 메인 프로그램에서 모든 함수를 통제하는 것이 아니라, 특정 하위 부분에 제어권을 넘겨주는 현상
- 콜백함수를 인자로 가지는 비동기 함수에게 제어권을 넘겨주기 때문에 발생
- 해당 비동기 함수가 제대로 처리되어 있지 않다면, 신뢰를 잃게 되고, 이를 보완하기 위해서 수많은 방어 로직을 만들어 재사용이 어렵게 된다.
5.2 프로미스를 통한 비동기제어
프로미스란 자바스크립트 비동기 처리에 사용되는 객체
[비동기 처리]
- 비동기 제어란, 비동기 함수가 가진 콜백함수들의 순서를 제어하는 것을 말한다.
- 자바스크립트의 비동기 처리란 특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미합니다. (ref. josha)
[프로미스 객체]
- 비동기 작업을 가진 “콜백함수”를 인자로 전달 받는다.
- 해당 콜백함수는 resolve와 reject 함수를 인자로 전달 받는다. (인자를 기본적으로 가지고 있는다.)
new Promise((resolve, reject) => { console.log('하나'); // 실패인 경우 reject() 함수를 호출하면 된다. // 그러면 then()을 건너뛰고 catch()가 실행된다. resolve(); })
[프로미스 상태]
- 비동기 처리 작업의 수행결과에 따라 resolve, reject 함수를 호출한다.
- 프로미스는 resolve, reject함수 호출 여부에 따라 3가지 상태를 가지게 된다.
- pending (resolve, reject 가 호출되지 않음)
- fulfilled ( 비동기 처리 성공하여 resolve 함수 호출된 상태)
- rejected (비동기 처리 실팽하여, reject 함수 호출된 상태)
- reject 상태가 된 경우,
catch()
를 통해 실패처리의 결과 값을 받을 수 있다. reject(new Error(”some Error”)
⇒ Error 객체를 넘겨 줌
[에러 처리]
then()
의 두번째 인자로 err를 처리하는 방법- resolve이후 수행되는 로직(체이닝 된 로직)에서 발생하는 error를 catch 할 수 없다.
catch()
를 통해 err를 처리하는 방법
[Promise.all]
- 전달받은 모든 프로미스를 병렬적으로 처리할 때 사용하는 메서드
- 모든 프로미스의 처리가 끝날 때 까지 기다린 이후, 모든 처리결과를 한 번에 resolve | reject 한다.
- 모든 프로미스가 resolve일 경우, 처리 결과를 배열에 담아 resolve 하는 프로미스 객체를 반환한다.
- 이때 첫번째 프로미스부터 차례대로 담기기 때문에, “처리 순서가 보장된다!”
- 하나라도 프로미스가 reject될 경우, 가장 먼저 실패한 프로미스가 reject한 error를 catch 하게 된다.
[Promise.race]
- Promise.all가 반대로, 가장 먼저 처리된 프로미스가, 결과 배열에 먼저 담기게 된다.
5.3 async await을 통한 비동기제어
- Es2017에 등장
- 프로미스의 then안에 프로미스가 연속해서 처리 될 경우 가독성 저하 문제
- 비동기 작업이 필요한 함수 앞에 await 키워드를 붙여 사용
- 비동기 작업의 결과를 기다렸다가 반환하게 됨
- Promise객체인 경우 resolve된 값을 반환
- 비동기작업들을 동기적 코드와 같이 보이도록 하여, 직관적인 이해 및 처리순서 보장 가능 장점
참고
수경 비동기
비동기
특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성을 의미한다.
동기적 처리의 단점은 하나의 작업이 너무 오래 걸리게 될 시, 모든 작업이 오래 걸리는 하나의 작업이 종료되기 전까지 올 스탑 되기 때문에, 전반적인 흐름이 느려진다.(성능상 문제)
[비동기 방식]
- 자바스크립트는 싱글 스레드 방식으로 동작 → 여러 개의 작업을 동시에 실행하게 함!
- 논블로킹방식
- 하나의 작업을 수행할 때 다른 작업을 수행하지 못하도록 블로킹 하지 않는 방식
JS 엔진은 어떻게 동기적 코드와 비동기적 코드를 구분해 수행하는가?(이벤트루프)

- 웹 API, 태스크 큐, 이벤트 루프 등으로 인해 단일 스레드 기반 Javascript도 비동기적으로 코드를 실행할 수 있다.
- Javascript 엔진
- JS코드를 읽고 해석해서 실행하는 것을 담당하는 인터프리터
- JS 엔진의 메모리 = Heap + Stack으로 구성
- Web API
- Ajax, setTimeout 등과 같이 웹 브라우저에서 제공하는 기능을 말한다.
- 이러한 요청들의 처리가 Javascript 엔진의 스레드와는 다른 스레드에서 이루어진다.
- JavaScript 엔진의 스택에서 실행된 비동기 함수가 요청하는 비동기 작업에 대한 정보와 콜백 함수를 웹 API를 통해 브라우저에게 넘기면, 브라우저는 이러한 요청들을 별도의 쓰레드에 위임 하게 되는 것이다.
- 그러면 그 스레드는 해당 요청이 완료되는 순간 전달받았던 콜백 함수를 JavaScript 엔진의 태스크 큐라는 곳에 집어넣는다.
- Task Queue
- JS엔진에 포함되어 있는 부분이며 웹 API를 처리하고 있던 스레드로부터 전달 받은 콜백 함수들을 저장하고 있는 큐를 말한다.
- 이벤트 루프
- JS엔진에 포함되어 있는 부분이며 매 순간 스택이 비어있는지 여부와 태스크 큐에 콜백 함수가 기다리고 있는지 여부를 확인하는 역할을 함
[콜백 지옥]
비동기 처리의 결과를 또 다른 비동기 처리의 결과로 이용하는 로직이 길어지는 현상을 콜백 헬이라고 한다. 이런 콜백 헬을 해결하기 위해 JS Promise 객체를 사용한다.
[Promise]
비동기 작업이 가질 수 있는 3가지 상태
- Pending(대기 상태), Fulfilled(성공), Rejected(실패)
- Pending → Fulfilled :
Resolve
(해결)
- Pending → Rejected :
Reject
(거부)

프로미스의 에러 처리 방법
- then()의 두 번째 인자로 처리
- catch()이용
function getData() { return new Promise(function(resolve, reject) { reject('failed'); }); } // 1. then()의 두 번째 인자로 에러를 처리하는 코드 getData().then(function() { // ... }, function(err) { console.log(err); }); // 2. catch()로 에러를 처리하는 코드 getData().then().catch(function(err) { console.log(err); });
가급적
.catch()
를 이용하는 것이 좋음. (댓글 내용 추가) then()
의 첫 번째 콜백 함수에서 오류가 나는 경우에 오류를 제대로 잡아내지 못하기 때문이다.[async & await]
기존의 비동기 처리 방식인 콜백 함수와 프로미스의 단점을 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다.
- 프로미스의 경우 .then을 계속 사용해서 코드가 길어질 가능성이 높다. async/await는 비동기 코드를 동기 코드처럼 읽히게 해주기 때문에 코드 흐름을 이해하기 쉽다.
- 프로미스는 .catch를 통해 에러 핸들링이 가능하지만 async/await는 에러 핸들링을 할 수 있는 기능이 없어 try-catch 문을 사용해야한다.
창민 비동기
동기와 비동기란 무엇인가요?
답변
동기란 현재 실행 중인 태스크가 종료할 때까지 다음에 실행될 태스크가 대기하는 방식이다
비동기는 현재 실행 중인 태스크가 종료되지 않은 상태라 해도 다음 태스크를 곧바로 실행하는 방식이다
프로미스란 무엇이고 어떻게 사용되나요?
답변
프로미스는 비동기 처리를 위한 ES6에서 도입된 표준 빌트인 객체이다
기존의 콜백 처리 방식의 문제를 극복하기 위해 도입되었다
Promise
생성자 함수를 통해 생성이 가능하다후속 처리 메서드를 사용해 비동기 처리 상태에 따라 선택적으로 콜백 함수가 호출되도록 할 수 있다
콜백 헬을 해결할 수 있는 방법은 무엇이 있을까요?
답변
프로미스 사용 혹은
async/await
사용?프로미스와
async/await
의 차이점은 무엇일까요?답변
에러 핸들링에서 차이가 있다
프로미스는 후속 처리 메서드
.catch()
로 에러 핸들링을 할 수 있다async/await
를 사용한다면 try-catch
문을 사용해 에러 핸들링을 해야한다는 차이가 있다