특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고 다음 코드를 먼저 실행하는 자바스크립트의 특성
ajax
보통 화면에 표시할 이미지나 데이터를 서버에서 불러와 표시해야 하는데 이때 ajax
통신으로 데이터를 서버에서 가져올 수 있다.
function getData() {
var tableData;
$.get('https://domain.com/products/1', function(response) {
tableData = response;
});
return tableData;
}
console.log(getData()); // undefined
ajax
요청을하고response
를 받아온 뒤tableData
를return
해야undefined
가 아닌 요청한 데이터를 확인할 수 있다.
하지만ajax
요청을 하고 난 뒤response
를 받아오기 전에return
이 됐다.
위처럼 비동기 처리는 로직을 끝날때 까지 다 기다리지 않고 뒤의 코드를 먼저 실행하는 것이다.
setTimeout()
코드를 바로 실행하지 않고 지정한 시간만큼 기다렸다가 로직을 실행시키는 API
// #1
console.log('Hello');
// #2
setTimeout(function() {
console.log('Bye');
}, 3000);
// #3
console.log('Hello Again');
실제 출력은
Hello
,Hello Again
, 3초 뒤Bye
순으로 출력된다.
비동기 처리로 이루어지기 때문에 3초를 기다렸다가Hello Again
이 먼저 출력되는 것이 아니라Bye
가 출력되고 3초가 지나면Hello Again
이 출력된다.
Callback
) 함수로 비동기 처리 방식 문제점 해결하기데이터를 받아오고 그 이후의 로직이 실행되거나, 일정 시간 이후에 진행되어야 하는 로직에 대해서는 비동기 처리 방식이 문제가 될 수 있다.
이러한 문제를 해결할 수 있는 방식이 callback
함수를 이용하는 것이다.
function getData(callbackFunc) {
$.get('https://domain.com/products/1', function(response) {
callbackFunc(response); // 서버에서 받은 데이터 response를 callbackFunc() 함수에 넘겨줌
});
}
getData(function(tableData) {
console.log(tableData); // $.get()의 response 값이 tableData에 전달됨
});
response
가 생성된 이후에callback
함수가 실행되기 때문에tableData
를 출력했을 때undefined
가 출력될 일이 없다.
비동기 처리 로직을 위해 콜백 함수를 연속해서 사용할 때 발생하는 문제
$.get('url', function(response) {
parseValue(response, function(id) {
auth(id, function(result) {
display(result, function(text) {
console.log(text);
});
});
});
});
데이터를 받아오거나, 인코딩, 인증 등의 모든 절차를 비동기로 처리해야하면 콜백 안에 콜백이 계속 생성되는 구조가 나타날 수 있다.
가독성도 떨어지고 로직 유지보수도 어렵다.
Promise
나 Async
를 사용하는 방법이 있다. 코딩 패턴만으로 콜백 지옥을 해결하려면 콜백 함수를 분리해주면 된다.
function parseValueDone(id) {
auth(id, authDone);
}
function authDone(result) {
display(result, displayDone);
}
function displayDone(text) {
console.log(text);
}
$.get('url', function(response) {
parseValue(response, parseValueDone);
});
하지만 Promise나 Async를 사용하면 더 편하게 콜백 지옥을 해결할 수 있다.
자바스크립트 비동기 처리에 사용되는 객체
주로 서버에서 받아온 데이터를 화면에 표시할 때 사용한다.
ajax + Promise
function getData(callback) {
// new Promise() 추가
return new Promise(function(resolve, reject) {
$.get('url 주소/products/1', function(response) {
// 데이터를 받으면 resolve() 호출
resolve(response);
});
});
}
// getData()의 실행이 끝나면 호출되는 then()
getData().then(function(tableData) {
// resolve()의 결과 값이 여기로 전달됨
console.log(tableData); // $.get()의 reponse 값이 tableData에 전달됨
});
Pending
(대기)resolve
, reject
new Promise();
Fulfilled
(이행)resolve
를 실행하면 이행 상태가 된다.then()
을 이용해서 처리 결과를 받을 수 있다.function getData() {
return new Promise(function(resolve, reject) {
var data = 100;
resolve(data);
});
}
// resolve()의 결과 값 data를 resolvedData로 받음
getData().then(function(resolvedData) {
console.log(resolvedData); // 100
});
Rejected
(실패)catch()
를 이용해서 실패한 이유(실패 처리 결과 값)를 받을 수 있다.function getData() {
return new Promise(function(resolve, reject) {
reject(new Error("Request is failed"));
});
}
// reject()의 결과 값 Error를 err에 받음
getData().then().catch(function(err) {
console.log(err); // Error: Request is failed
});
then()
이나catch()
를 호출하고 나면 새로운Promise
객체가 반환된다.
해당 객체를 통해서 추가적인then()
,catch()
가 가능하다.
Promise Chaining
)function getData() {
return new Promise({
// ...
});
}
// then() 으로 여러 개의 프로미스를 연결한 형식
getData()
.then(function(data) {
// ...
})
.then(function() {
// ...
})
.then(function() {
// ...
});
then()
의 두 번째 인자로 에러를 처리하는 방법catch()
를 이용하는 방법가급적으로
catch()
로 처리하는 것이 더 효율적이다.
then()
의 두 번째 인자로 에러를 처리하는 방법보다 더 많은 상황을 예외 처리할 수 있다.
기존의 비동기 처리 방식인 Callback
함수와 Promise
의 단점은 보완하고 개발자가 읽기 좋은 코드를 작성할 수 있게 도와준다.
callback
함수를 이용했을 때function logName() {
// 아래의 user 변수는 위의 코드와 비교하기 위해 일부러 남겨놓았습니다.
var user = fetchUser('domain.com/users/1', function(user) {
if (user.id === 1) {
console.log(user.name);
}
});
}
async & await
를 이용했을 때async function logName() {
var user = await fetchUser('domain.com/users/1');
if (user.id === 1) {
console.log(user.name);
}
}
함수명 앞에
async
를 붙이고, 비동기 처리 코드 앞에await
를 붙인다.
비동기 처리 메서드가 꼭 프로미스 객체를 반환해야await
가 의도한 대로 동작한다.
await
의 대상이 되는 비동기 처리 코드는axios
등 프로미스를 반환하는API
이다.
async & await
예제function fetchItems() {
return new Promise(function(resolve, reject) {
var items = [1,2,3];
resolve(items)
});
}
async function logItems() {
var resultItems = await fetchItems();
console.log(resultItems); // [1,2,3]
}
logItems()
에 프로미스를 사용한다면?fetchItems().then(function(items) {
var resultItems = items;
console.log(resultItems);
}
function fetchUser() {
var url = 'https://jsonplaceholder.typicode.com/users/1'
return fetch(url).then(function(response) {
return response.json();
});
}
function fetchTodo() {
var url = 'https://jsonplaceholder.typicode.com/todos/1';
return fetch(url).then(function(response) {
return response.json();
});
}
async function logTodoTitle() {
var user = await fetchUser();
if (user.id === 1) {
var todo = await fetchTodo();
console.log(todo.title); // delectus aut autem
}
}
비동기 처리 코드를 콜백이나 프로미스로 했다면 훨씬 코드가 길어졌을 것이다.
async & await
문법을 이용하면 기존의 비동기 처리 코드 방식으로 사고하지 않아도 되는 장점이 생긴다.
try catch를 이용해서 예외처리를 한다.
async function logTodoTitle() {
try {
var user = await fetchUser();
if (user.id === 1) {
var todo = await fetchTodo();
console.log(todo.title); // delectus aut autem
}
} catch (error) {
console.log(error);
}
}
네트워크 통신 오류뿐만 아니라 간단한 타입 오류 등의 일반적인 오류까지도
catch
로 잡아낼 수 있다.
발견된 에러는error
객체에 담기기 때문에 에러 유형에 맞게 에러 코드를 처리해주면 된다.
자바스크립트 비동기 처리와 콜백 함수
자바스크립트 Promise 쉽게 이해하기
자바스크립트 async와 await