자바스크립트 동작원리 비동기처리 part2
비동기적 자바스크립트
비동기처리란 특정 코드가 종료되지 않았어도 대기하지 않고 다음 코드를 실행하는 자바스크립트의 특성이다.
동기식 (Synchronous)
먼저 시작된 하나의 작업이 끝날 때까지 다른 작업을 시작하지 않고 기다렸다가 다 끝나면 새로운 작업을 시작하는 방식이다.
위 그림 Synchronous와 같이 작업이 직렬로 배치되어 실행되며 작업 실행의 순서가 확실히 정해져 있는 것을 동기식 처리라 부른다.
비동기식 (Asynchronous)
동기식 방식과는 다르게 먼저 시작된 작업의 완료 여부와는 상관없이 새로운 작업을 시작하는 방식이다.
위 그림 Asynchronous와 같이 작업이 병렬로 배치되어 실행되며 작업의 순서가 확실하지 않아 나중에 시작된 작업이 먼저 끝나는 경우도 발생한다.
이와 같은 방식을 비동기식 처리라 부른다.
이번에는 아래의 코드가 어떻게 비동기로 작동하는지 자세히 알아보자.
console.log("시작");
setTimeout(function(){
console.log("3초후 실행");
}, 3000);
console.log("끝");
// 시작
// 끝
// 3초후 실행
자바스크립트 비동기 처리 방식
- 콜백 함수 사용
- Promise
- Promise를 활용한 async/await
1. 콜백 함수 사용
- 콜백 함수를 사용하지 않을 경우
// 콜백 함수
function printString(callbackParam) {
console.log(callbackParam);
}
// 콜백 함수 호출
function callHello() {
let value;
console.log("Wait 3 sec.");
console.log('waiting...');
setTimeout(function() {
value = 'Hello';
}, 3000);
return value;
}
// 실행
const r = callHello();
printString(r);
- 결과
# 시작
Wait 3 sec.
waiting...
undefined
(3초 대기)
# 종료
- 콜백 함수를 사용할 경우
// 콜백 함수
function printString(callbackParam) {
console.log(callbackParam);
}
// 콜백 함수 호출
function printString(callbackParam) {
console.log(callbackParam);
}
function callPrint(callback) {
let value;
console.log("Wait 3 sec.");
console.log("waiting...");
setTimeout(function() {
value = "Hello";
callback(value);
}, 3000);
}
// 실행
callPrint(printString);
- 결과
# 시작
Wait 3 sec.
waiting...
(3초 대기)
Hello
# 종료
콜백 함수를 사용하면 위 결과에서 볼 수 있듯이 setTimeout()에 의해 3초간 대기 후 콜백 함수로 전달된 printString()을 실행하여 Hello를 출력하게 된다(callback은 또 동기적,비동기적으로 나뉜다)
그러나 위의 예제와 다르게 실제로 개발을 하다 보면 콜백 함수가 복잡해지는 경우가 많아진다.
소위 말하는 콜백 지옥(Callback hell)에 빠지는 경우가 생길 수 있다.
a(function (resultsFromA) {
b(resultsFromA, function (resultsFromB) {
c(resultsFromB, function (resultsFromC) {
d(resultsFromC, function (resultsFromD) {
e(resultsFromD, function (resultsFromE) {
f(resultsFromE, function (resultsFromF) {
console.log(resultFromF);
})
})
})
})
})
});
이렇듯 콜백 함수를 남용하게 되면 가독성과 에러 처리 등에서 불편함이 발생한다.
이를 해소하기 위해 ES6에서 비동기 처리의 새로운 방법으로 Promise 객체가 등장한다.
ES6부터 추가된 프로미스(Promise)
Promise는 latency, delay(지연) 때문에 현재 당장 얻을 수 없지만 가까운 미래에 얻을 수 있는 데이터에 접근하기 위한 방법을 제공한다. Promise로 비동기 작업이 완료된 후 결과 값을 받을 수 있다.
Promise 생성 및 상태
Promise는 new Promise()로 생성할 수 있으며, 종료될 때 세 가지 상태를 갖는다.
- Pending(대기): 이행하거나 거부되지 않은 초기 상태
- Fulfilled(이행): 완료되어 프로미스가 결과 값을 반환해준 상태
- Rejected(거부): 실패하거나 오류가 발생항 상태
Promise는 resolve와 reject 2개의 인자를 받으며,
비동기 처리가 성공하면 resolve가 호출되고, 실패하면 reject가 호출된다.
const promise = new Promise((res, rej) => {
setTimeout(() => {
res('성공')
}, 1000)
})
Promise Chaining
Promise의 또 다른 특징은 체이닝(chaining)인데, .then()을 이용해서 여러개의 Promise를 이을 수 있다는 것이다.
new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(0)
}, 2000)
})
.then(function(result) {
console.log(result) // output: 0
return result + 10
})
.then(function(result) {
console.log(result) // output: 10
return result + 20
})
.then(function(result) {
console.log(result) // output: 30
})
Promise에서 에러 처리를 할 수도 있는데 보통 catch()를 사용한다.
const promise = new Promise((res, rej) => {
setTimeout(() => {
rej('에러 발생')
}, 1000)
})
promise.then(res => console.log(res)).catch(err => console.error(err))
// output: 에러 발생
어떤게 먼저 실행될까?
console.log('hi')
setTimeout(function() {
console.log('0.1')
}, 100)
Promise.resolve()
.then(function() {
console.log('first')
})
.then(function() {
console.log('second')
})
setTimeout(function() {
console.log('0')
}, 0)
console.log('end')
실행결과
hi
end
first
second
0
0.1
setTimeout()과 Promise는 모두 비동기 함수이지만, setTimeout은 태스크 큐지만, Promise는 비동기 중에서도 먼저 실행되는 마이크로태스크 큐에 들어있기 때문에 먼저 실행이 된다. 이벤트 루프는 콜 스택이 비면 먼저 마이크로태스크 큐에서 대기하고 있는 함수를 실행 하고, 이후에 태스크 큐에서 대기하고 있는 함수를 가져와 실행한다.
async await
async await를 ES2017에 등장한 것인데, Promise의 메서드 체이닝을 더 깔끔한 코드를 작성할 수 있게끔 만들어진 것이다.
async await의 기본 구조를 아래와 같다.
const getSomthing = async () => {
await doSomething()
}
async await는 try와 catch로 성공 및 에러 여부를 감지할 수 있다.
Promise와 async await의 코드 차이를 한번에 보자.
Promise
const promise = new Promise((res, rej) => {
console.log('first')
setTimeout(() => {
res('2초 후')
}, 2000)
console.log('end of function')
})
promise.then(res => console.log(res)).catch(err => console.error(err)
async await
const asyncFunc = async () => {
try {
console.log('first')
await setTimeout(() => console.log('2초 후'), 2000)
} catch (err) {
console.log(err)
}
console.log('end of function')
}
asyncFunc()
두 함수의 결과 모두 first, end of function이 바로 찍히고, 2초 후에 2초 후가 console에 찍힌다.
같은 비동기 함수임에도 async await을 사용하면 코드를 더 깔끔하게 작성할 수 있다.
출저 : [JS] Javascript 동작 원리와 비동기처리 | INGG.
[JS] Javascript 동작 원리와 비동기처리
자바스크립트는 싱글스레드이다. 어떻게 자바스크립트는 싱글스레드이면서 비동기인 것일까? 자바스크립트가 어떻게 동작하는지 내부 원리에 대해 알아보자. 📌 Contents 자바스크립트 엔진 자
ingg.dev
출저 : 자바스크립트 비동기 함수 알아보기 | MJ Kim (howdy-mj.me)
자바스크립트 비동기 함수 알아보기
비동기(Asynchronous…
www.howdy-mj.me