동기(sync)와 비동기(async)
데이터를 받아오는 방식에는 동기식 처리 방법과 비동기식 처리 방법이 존재한다.
동기(synchronous)
동기는 데이터의 요청과 결과가 한 자리에서 동시에 일어나는것을 말한다.
사용자가 데이터를 서버에게 요청한다면 그 서버가 데이터 요청에 따른 응답을 사용자에게 다시 리턴해주기 전까지 사용자는 다른 활동을 할 수 없으며 기다려야만한다. 순서에 맞춰 진행되는 장점이 있지만, 여러 가지 요청을 동시에 처리할 수 없다.
장점: 순서에 맞춰 진행, 설계가 매우 간단하고 직관적이다.
단점: 여러 가지 요청을 동시에 처리할 수 없음
비동기(Asynchronous)
비동기는 데이터의 요청과 결과가 동시에 일어나지 않는다는 것을 의미한다.
사용자가 서버에게 데이터를 요청한 후 요청에 따른 응답을 계속 기다리지 않아도 다른 외부 활동을 수행할 수 있고 서버에게 다른 요청사항을 보낼 수 있다.
장점 : 요청에 따른 결과가 반환되는 시간 동안 다른 작업을 수행할 수 있다.
단점 : 동기식보다 설계가 복잡하다. 언제 코드가 실행될지 예측할 수 없다.
자바스크립트는?
자바스크립트는 호이스팅(함수 선언들이 자동적으로 제일 먼저 선언) 된 순서 부터 동기적으로 실행된다.
async & await
promise를 깔끔하게 사용하는 방법.
1. async
function fetchUser() {
return new Promise((resolve, reject) => {
// do network reqeust in 10 secs...
resolve('hello');
});
}
const user = fetchUser();
user.then(console.log);
console.log(user);
⬇️
async function fetchUser() {
// do network reqeust in 10 secs...
return 'hello';
}
const user = fetchUser();
user.then(console.log);
console.log(user);
Promise를 더 간단하게 사용하기 위해서는 async 키워드를 함수 앞에 붙여주면 코드 블록이 자동으로 Promise로 바뀐다.
2. await
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sayHello() {
await delay(1000);
return 'Hello';
}
async function isName() {
await delay(1000);
return 'Jake';
}
// Promise. async 사용 전
// funtion isName() {
// return delay(1000)
// .then(() => 'Jake');
// }
await을 사용하면 1초가 끝날때까지 기다려 준다. 따라서 1초 후 Hello, 또 1초 후 Jake가 출력된다.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sayHello() {
await delay(1000);
return 'Hello';
}
async function isName() {
await delay(1000);
return 'Jake';
}
function sayHelloJake() {
return sayHello().then(hello => {
return isName().then(name => `${Hello} + ${Jake}`);
});
}
sayHelloJake().then(console.log)
Hello와 Jake를 동시에 출력하고 싶을 때 중첩하여 사용한다.
하지만 Promise도 너무 중첩적으로 사용하면 콜백지옥과 비슷한 문제점 발생한다.
⬇️
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sayHello() {
await delay(1000);
return 'Hello';
}
async function isName() {
await delay(1000);
return 'Jake';
}
async function sayHelloJake() {
const hello = await sayHello();
const name = await isName();
return `${Hello} + ${Jake}`;
}
sayHelloJake().then(console.log)
async await를 사용하여 깔끔하게 사용 가능하다.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sayHello() {
await delay(1000);
throw 'error';
return 'Hello';
}
async function isName() {
await delay(1000);
return 'Jake';
}
async function sayHelloJake() {
try{
const hello = await sayHello();
const name = await isName();
} catch() {
console.log('error')
};
return `${Hello} + ${Jake}`;
}
sayHelloJake().then(console.log)
만약 에러가 발생했다면 try catch를 이용해서 에러 처리를 할 수 있다.
문제점: Hello를 받는데 1초, Jake를 받는데 1초가 걸린다.
2초는 문제점을 못 느낄 수도 있지만 만약 한 데이터를 받아올 때까지 10초가 걸린다고 가정한다면 20초가 걸리는 시간동안
사용자는 빈 화면만 보게 된다. 따라서 이 때 병렬적 구조를 통해 동시에 데이터를 받아오면 시간을 더 단축할 수 있다.
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sayHello() {
await delay(1000);
throw 'error';
return 'Hello';
}
async function isName() {
await delay(1000);
return 'Jake';
}
// 1번
async function sayHelloJake() {
const helloPromise = sayHello();
const namePromise = isName();
const hello = await helloPromise();
const name = await namePromise();
return `${Hello} + ${Jake}`;
}
// 2번⭐️
funtion sayHelloJake() {
return Promise.all([sayHello(), isName()])
.then(name => name.join(' + ')
);
}
sayHelloJake().then(console.log)
두 가지의 데이터를 받아 올 때 서로 연관되지 않아 동시에 불러올 수 있는 Promise는 1번처럼 사용하지 않는다.
유용한 API
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function sayHello() {
await delay(2000);
return 'Hello';
}
async function isName() {
await delay(1000);
return 'Jake';
}
function pickName() {
return Promise.race([sayHello(), isName()]); // 먼저 출력 되는 값만 출력
}
sayHelloJake().then(console.log)
⭐️⭐️⭐️중요⭐️⭐️⭐️
- 동기와 비동기는 어떤 작업 혹은 그와 연관된 작업을 처리하고자 하는 목적의 차이이다.
- 동기는 추구하는 행위 와 목적이 동시에 이루어지고 여러 가지 요청을 동시에 처리할 수 없다.
- 비동기는 추구하는 행위 와 목적이 다를 수도 있고, 요청에 따른 결과가 반환되는 시간 동안 다른 작업을 수행할 수 있다.