1. 동기(Sync)와 비동기(Async)에 대한 개념
- 일반적으로 '동기로 실행된다' 라고 함은 먼저 실행된 코드의 결과가 나올때 까지 대기하는것
=> 마트 계산대에서 먼저 온 손님부터 한명씩 계산한다는 개념
- '비동기로 실행된다' 라는 것은 실행된 순서와 관계 없이 결과가 나오는 것을 말한다.
=> 정원이 정해진 식당에 입장은 선착순이고 퇴장순서는 식사가 끝난수 인데 식사시간은 사람마다 다르므로 입/퇴장이 비동기적처리된다고 볼 수 있다.
2. Blocking Model & Non-Blocking Model
- Blocking Model
코드의 실행이 끝나기 전까지 실행 제어권을 다른곳에 넘기지 않고 대기하는 것
- Non-Blocking Model
코드의 실행이 끝나지 않아도 실행 제어권을 다른곳에 넘겨 다음 코드가 실행될수 있는것
- 차이점 ?
제어권을 넘기면 다른코드도 실행될수 있어 비동기 처리가 가능하지만
넘기지 않으면 비동기처리가 가능한환경이어도 비동기 처리가 불가능
- JavaScript는 Async + Non-Blocking Model을 채용하여 현재 실행중인 코드의 실행이 끝나지 않아도 다음코드를 호출한다.
=> 각 명령들이 순서대로 실행될 수 있게 구현되어 있지만, Non-Blocking Model에 의해 명령이 아닌 모든 함수는 비동기적으로 실행된다.
- 예시 (setTimeout 은 특정 시간 뒤에 함수를 실행해주는 역할.)
function first() {
console.log('First');
}
setTimeout(first, 1000); // 1000ms(1초) 뒤에 first 함수를 실행해준다.
console.log('Middle');
console.log('Last');
// Print: Middle
// Last
// First
아래 순서대로 실행된다.
1. setTimeout(first, 1000) : 1초 뒤에 first() 함수 -> console.log('first')가 실행되도록 명령
2. console.log('Middle') : 'Middle' 문자열이 출력
3. console.log('Last') : 'Last' 문자열이 출력
4. 1초가 지난 뒤 'First' 문자열이 출력된다.
- 만약 JS가 Blocking Model 이었다면 위 예시 코드는 1초를 기다린 이후에 first() 함수를 먼저 실행한뒤 나머지 순서로 출력했을 것.
3. Promise
- JS에서 비동기 처리를 동기로 처리할 수 있게 돕는 객체유형
- Promise 생성자 인터페이스
생성자란(Constructor) ?
JS에서는 원시 타입(String, Boolean 등)을 제외한 대부분의 타입들이 객체(Object)로 구성되어 있다.
일반적으로 객체를 생성하는 함수를 생성자(Constructor) 함수라고 부르게 되는데, 프로미스 또한 객체로 구성되어 있기 때문에 생성자 함수를 이용해 프로미스를 선언하게 된다.
function printFunc(data){
console.log(data);
}
// 생성자 함수
const obj = new Object();
const promise = new Promise(printFunc);
obj
// Print : {}
new Promise(executor);
// 예제
new Promise((resolve, reject) => {
// 명령문
});
- 프로미스의 상태
반드시 3가지 상태를 지니며, 대기(Pending) 상태가 아니라면 Promise의 연산이 이미 끝난 상태로 볼수 있다
- 대기(Pending): 이행하거나 거부되지 않은 초기 상태.
- 이행(Fulfilled): 연산이 성공적으로 완료됨.
- 거부(Rejected): 연산이 실패함.
프로미스가 만들어 질 때 executor가 실행되며, executor에서 resolve 함수가 호출되지 전까지 firstPromise.then(...) 안에 있는 코드를 실행하지 않는다.
이렇게 executor 가 실행되어 resovle된 프로미스를 Fulfilled Promise라고 부른다.
const timerPromise = new Promise((resolve, reject) => { // 이곳에 정의된 함수가 executor
setTimeout(() => {
console.log('First');
resolve();
}, 1000);
});
// 이 시점에서 timerPromise는 Fulfilled Promise라고 부를 수 있다.
timerPromise.then(() => {
console.log('Middle');
console.log('Last');
});
// Print: First
// Middle
// Last
- Promise.then
Promise 안에서 resolve가 실행 된 경우 then 메서드에 작성된 함수가 실행된다.
const resolvePromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('First');
resolve('Resolve!'); // resolve를 실행할 때, 안에 데이터를 넣어줄 수 있습니다.
}, 1000);
});
resolvePromise.then((data) => {
console.log('Middle');
console.log('Last');
console.log(data);
})
// Print: First -> 1초 뒤에 출력됩니다.
// Middle
// Last
// Resolve!
- Promise.catch
Promise 안에서 에러가 throw 되거나 reject되면 catch메서드에 작성한 함수가 실행
const errorPromise = new Promise((resolve, reject) => {
setTimeout(() => {
console.log('First');
reject('Error!!'); // 직접 reject를 실행하면 프로미스에서 에러가 발생한것으로 간주됩니다.
}, 1000);
});
errorPromise.then(() => {
console.log('Middle');
console.log('Last');
}).catch((error) => {
console.log('에러 발생!', error);
});
// Print: '에러 발생! Error!!'
Promise.then 더 알아보기
1) Promise에서 resolve된 값 이용하는 방법
const firstPromise = new Promise((resolve, reject) => {
resolve('First');
});
firstPromise.then((value) => {
console.log(value);
});
// Print: 'First'
2) Promise.resolve 함수 이용
- 프로미스가 값을 반환하는 경우 반환하는 값은 항상 프로미스로 감싸져 있다.
const firstPromise = Promise.resolve('First');
firstPromise.then((value) => {
console.log(value);
});
// Print: 'First'
3) Promise.then으로 함수형 프로그래밍 체험하기
- 가능한 이유는 console.log라는 함수 뒤에 괄호를 사용해서 함수를 호출하지 않고 함수 그대로 then 에 넘겼기 때문
const firstPromise = Promise.resolve('First');
firstPromise.then(console.log);
// Print: 'First'
4) Promise.then으로 함수형 프로그래밍 체험하기 2
const countPromise = Promise.resolve(0);
function increment(value) {
return value + 1;
}
const resultPromise = countPromise.then(increment).then(increment).then(increment);
resultPromise.then(console.log);
// Print: 3
5) 기타 유용한 프로미스 함수
- Promise.all (https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/all)
- Promise.rece (https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/race)
4. 비동기 함수 (Async Function)
특징
- 비동기 함수는 일반 함수나 화살표 함수와 비슷하지만 크게 두가지가 다르다.
- 비동기 함수의 결과 값은 항상 Promise 객체로 resolve 된다.
- 비동기 함수 안에서만 await 연산자를 사용할수 있다. (ES6 기준)
- 이 특징들을 제외하면 기존 일반 함수나 화살표 함수처럼 사용가능하다.
- 아래 세가지 함수 결과 값은 Promise로 받는다.
// 비동기 + 일반 함수
async function 함수이름() {
// 명령문
}
// 비동기 + 익명 함수
async function() {
// 명령문
}
// 비동기 + 화살표 함수
async () => {
// 명령문
}
이러한 특징을 아래처럼 작성하는 것과 비슷하다
function 함수이름() {
return Promise.resolve('값');
}
// 위와 아래의 함수는 같은 동작을 보여준다.
async function 함수이름2() {
return '값';
}
함수이름();
// Print: Promise { '값' }
함수이름2();
// Print: Promise { '값' }
- 비동기 함수를 쓰는 이유 ?
await 연산자를 비동기 함수와 함께 씀으로써 문법이 간결해진다.
new Promise(executor) 코드로 Promise를 직접 생성하면 executor가 바로 실행 되지만 비동기 함수는 함수가 실행되기 전까지 Promise를 생성하지 않는다.
- 자바스크립트가 비동기처럼 실행될수 있는 원리
- Callback : https://developer.mozilla.org/en-US/docs/Glossary/Callback_function
- Event loop : https://developer.mozilla.org/ko/docs/Web/JavaScript/EventLoop
- Call stack : https://developer.mozilla.org/ko/docs/Glossary/Call_stac
5. await 연산자
- Promise가 fulfill되거나 rejected될 때 까지 함수의 실행을 중단하고 기다릴 수 있다.
- 연산이 끝나면 함수에서 반환한 값을 얻을 수 있다
- async 함수 안에서만 사용할 수 있다 (ES6 기준)
- 인터페이스
const result = await 값;
- '값' 에는 Promise가 아닌 다른 값도 들어갈 수 있다.
- Promise가 아니라면 기다리지 않고 해당 값 자체를 그대로 반환.
async function 함수이름() {
const result = await 'Test!';
console.log(result);
}
함수이름();
// Print: 'Test!';
※ ES6 기준 이라고 쓴 이유
'Language > Javascript' 카테고리의 다른 글
06-1 객체의 기본 (0) | 2022.10.05 |
---|---|
ES의 의미와 ES5,ES6 차이점 (0) | 2022.10.02 |
구조 분해 할당 (0) | 2022.09.30 |
함수 (0) | 2022.09.30 |
JavaScript 기초 1 (2) | 2022.09.23 |