기본적으로 웹 애플리케이션에서 서버 쪽 데이터가 필요할 때는 Ajax 기법을 사용하여 서버의 API를 호출함으로써 데이터를 수신한다.
서버의 API를 이용할 때는 네트워크 응답 시간이 필요하다. 이 과정에서 비동기적으로 처리하게 된다.
만약 작업을 동기적으로 처리한다면 해당 요청이 끝날 때까지 다른 요청을 수행할 수 없다.
비동기적으로 진행한다면 동시에 여러 요청을 수행할 수 있고, 기다리는 과정에서 다른 함수를 호출할수도 있다.
일반적으로 자바스크립트의 비동기 처리 코드는 콜백을 사용해야 코드의 실행순서를 보장받을 수 있다.
setTimeout 함수의 경우에는 특정 작업을 예약할 수 있다.
setTimeout 함수가 호출되면 코드가 멈추는 것이 아니라 그 다음 코드가 호출되고 지정한 시간이 지난 후에 setTimeout에 작성된 함수가 실행된다.
이렇게 지정한 시간 뒤에 실행될 (작성된) 함수가 콜백함수이다.
비동기 처리에 사용되는 객체
비동기 처리: 특정 코드의 실행이 완료될 때까지 기다리지 않고 다음 코드를 먼저 수행하는 특성
주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다. (일반적으로 웹 애플리케이션을 구현할 때 서버에서 데이터를 요청하고 받아오기 위해 API를 사용한다.)
요청에 대한 응답(데이터)이 오기도 전에 데이터를 화면에 표시하려고 하면 오류가 발생하거나 빈 화면이 나오는데 이와 같은 문제점을 해결하기 위한 방법으로 promise를 사용한다.
콜백함수 안에 콜백을 넣어서 구현할 수 있다. 하지만 계속 중첩되면 코드의 가독성이 나빠진다.
이러한 형태를 '콜백 지옥'이라고 한다. '콜백 지옥' 같은 코드가 형성되지 않게 하기 위해서 ES6에서 도입된 기능이다.
function increase(number) {
const promise = new Promise((resolve, reject) => {
// resolve: 성공, reject: 실패
setTimeout(() => {
const result = number + 10;
if (result > 50) {
const e = new Error('NumberTooBig');
return reject(e);
}
resolve(result);
}, 1000);
});
return promise;
}
increase(0)
.then((number) => {
return increase(number);
})
.then((number) => {
return increase(number);
})
.catch((e) => {
console.log(e);
});
여러 작업을 연달아 처리하지만 함수를 여러번 감싸는 것이 아니라 그 다음 작업으로 설정하기 때문에 콜백 지옥이 형성되지 않는다.
Pending(대기): 비동기 처리 로직이 완료되지 않은 상태
new Promise((resolve, reject) => {});
Fulfilled(이행): 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
new Promise((resolve, reject) => {
resolve();
});
이행 상태가 되면 then()을 사용해서 처리 결과 값을 받을 수 있다.
Rejected(실패): 비동기 처리가 실패하거나 오류가 발생한 상태
new Promise((resolve, reject) => {
reject();
});
실패 상태가 되면 실패한 이유를 catch()로 받을 수 있다.
Promise를 더욱 쉽게 사용할 수 있도록 해주는 ES2017(ES8) 문법이다.
이 문법을 사용하려면 함수의 앞부분에 async 키워드를 추가하고 함수 내부에 Promise 앞 부분에 await 키워드를 사용한다.
기본적으로 비동기 코드를 쓰고 Promise를 더 읽기 쉽도록 만들어준다.
async 키워드를 붙여주면 Promise를 반환한다.
let hello = async () => { return "Hello" };
hello().then((value) => console.log(value))
결과를 직접반환하는게 아니라 Promise를 반환하게 된다.
async function hello() {
return greeting = await Promise.resolve("Hello");
};
hello().then(alert);
axios는 가장 많이 사용되고 있는 자바스크립트 HTTP 클라이언트이다.
이 라이브러리의 특징은 HTTP 요청을 Promise 기반으로 처리한다.
$yarn add axios
App.js
import React, { useState } from 'react';
import axios from 'axios';
const App = () => {
const [data, setData] = useState(null);
const onClick = () => {
axios
.get('https://jsonplaceholder.typicode.com/todos/1')
.then((response) => {
setData(response.data);
});
};
return (
<div>
<div>
<button onClick={onClick}>불러오기</button>
</div>
{data && (
<textarea
rows={7}
value={JSON.stringify(data, null, 2)}
readOnly={true}
/>
)}
</div>
);
};
export default App;
const onClick = async () => {
try {
const response = await axios.get(
'https://jsonplaceholder.typicode.com/todos/1',
);
setData(response.data);
} catch (e) {
console.log(e);
}
};
함수 앞에 async를 작성하고 Promise 객체가 반환되는 곳(대부분 API) 앞에 await를 작성한다. then()을 사용하지 않아도 되는 이유는 async/await가 없으면 then을 통해서 Promise객체가 반환됐을 때를 알고 setData를 해줄 수 있다.
await를 통해서 setData 함수의 실행을 지연시킬 수 있다.