
이번 포스팅에서 promise, async await의 차이점을 알아보자!
1. 자바스크립트에서 비동기 처리가 필요한 이유
- js는 동기적인 언어이나 대기시간이 긴 작업(서버에 데이터를 요청하는 작업)을 하는 경우 비동기 작업을 하기도 한다.
- 아래는 비동기 처리가 필요한 간단한 예시이다.
- getHotels()는 서버에서 호텔의 데이터를 받아오는 함수이다.
- 그리고 우리는 getHotels()의 응답값을 받아 출력하고 싶다.
function printHotels() {
const hotels = getHotels();
console.log(hotels);
}
위와 같이 작성하면 Hotels()의 값이 출력될까?
- 답은 No
- 왜? 자바스크립트는 기본적으로 동기적인 언어이지만, 대기시간 긴 작업의 경우 비동기로 작업하기 때문에 getHotels()보다 콘솔 출력이 먼저 발생하기 때문에 콘솔창에는 undefined가 출력된다.
function printHotels() {
const hotels = getHotels(); // 이것봐라? 대기 시간이 너무 기네?
console.log(hotels); // 그럼 해당 출력 코드 먼저 실행하자
}
printAnimals(); // undefined
- 그렇다면 getHotels()의 응답값(response)를 사용하고 싶다면 어떤 조치를 취해줘야 할까?
- 바로 이 때 비동기 처리방식 promise, async await를 사용해 준다. 그렇다면 이들의 차이점은?
아래는 자바스크립트에서 비동기 처리가 필요한 몇 가지 예시이다.
1. 서버로부터 데이터 가져오기 (AJAX 요청)
2. 파일 읽기/쓰기
3. 타이머 함수 사용
4. Promise와 async/await 사용
1-1. 서버로부터 데이터 가져오기 (AJAX 요청)
웹 애플리케이션에서 서버로부터 데이터를 가져오는 작업은 시간이 오래 걸릴 수 있다. 이 작업을 동기로 처리하면 데이터가 도착할 때까지 다른 모든 작업이 블록된다.
[잘못된 예시]
// 동기적 처리 예시 (나쁜 예시)
function fetchDataSync() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", false); // false: 동기적
xhr.send(null);
if (xhr.status === 200) {
console.log(xhr.responseText);
}
}
fetchDataSync();
console.log("이 메시지는 데이터가 모두 로드된 후에야 출력됩니다."); // 이 메시지는 데이터가 도착한 후에 출력됨
위 코드를 아래처럼 비동기적으로 처리하면 다른 작업이 블록되지 않는다.
[좋은 예시]
// 비동기적 처리 예시 (좋은 예시)
function fetchDataAsync() {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", true); // true: 비동기적
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
console.log(xhr.responseText);
}
};
xhr.send(null);
}
fetchDataAsync();
console.log("이 메시지는 데이터가 로드되기 전에 출력될 수 있습니다."); // 이 메시지는 즉시 출력됨
1-2. 파일 읽기/쓰기
파일 시스템에 접근하는 작업은 오래 걸릴 수 있다. 이를 비동기적으로 처리하지 않으면 파일 읽기/쓰기 작업이 완료될 때까지 자바스크립트가 멈춘다.
[잘못된 예시]
const fs = require('fs');
// 동기적 파일 읽기 (나쁜 예시)
function readFileSync() {
const data = fs.readFileSync('/path/to/file', 'utf8');
console.log(data);
}
readFileSync();
console.log("이 메시지는 파일이 모두 읽힌 후에야 출력됩니다."); // 이 메시지는 파일이 읽힌 후에 출력됨
[좋은 예시]
// 비동기적 파일 읽기 (좋은 예시)
function readFileAsync() {
fs.readFile('/path/to/file', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
}
readFileAsync();
console.log("이 메시지는 파일이 읽히기 전에 출력될 수 있습니다."); // 이 메시지는 즉시 출력됨
1-3. 타이머 함수 사용
타이머 함수(setTimeout, setInterval)는 일정 시간이 지난 후에 특정 작업을 수행해야 할 때 유용하다. (비동기적 작동)
// setTimeout을 사용한 비동기 처리
console.log("이 메시지는 즉시 출력됩니다.");
setTimeout(() => {
console.log("이 메시지는 2초 후에 출력됩니다.");
}, 2000);
console.log("이 메시지도 즉시 출력됩니다."); // 이 메시지는 setTimeout 콜백 이전에 출력됨
1-4. Promise와 async/await 사용
비동기 처리를 위해 Promise와 async/await를 사용하면 코드 가독성이 향상됨.
// Promise를 사용한 비동기 처리
function fetchData() {
return new Promise((resolve, reject) => {
var xhr = new XMLHttpRequest();
xhr.open("GET", "https://api.example.com/data", true);
xhr.onreadystatechange = function() {
if (xhr.readyState === 4 && xhr.status === 200) {
resolve(xhr.responseText);
} else if (xhr.readyState === 4) {
reject("Error fetching data");
}
};
xhr.send(null);
});
}
fetchData()
.then(data => {
console.log(data);
})
.catch(error => {
console.error(error);
});
// async/await를 사용한 비동기 처리
async function fetchDataAsync() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error(error);
}
}
fetchDataAsync();
console.log("이 메시지는 fetchDataAsync 호출 후에 즉시 출력됩니다."); // 이 메시지는 즉시 출력됨
2. promise vs async await
2-1. async를 사용하면 코드가 간결하다.
- 앞선 예시 getHotels()를 호출하여 응답값을 받고, 이 응답값을 출력하고자 한다.
- promise의 then방식의 코드는 아래와 같다.
function print Hotels() {
getHotels().then((data) => {
console.log(data);
})
}
- 이 코드를 async await로 바꾸고 싶다. => 함수에 async 키워드를 적고, 비동기 대상에 await를 추가
- 비동기 대상 함수에 await를 추가는 것 => '해당 함수의 처리를 기다려!'
- 그리고 await 함수 아래에 해당 함수의 응답값을 사용하는 구문을 추가해주자.
async function printHotels() {
const hotels = await getHotels(); // 해당 함수처리 끝날때까지 기다려!
console.log(hotels) // 응답값 출력됨
}
여기까지는 코드가 별로 길지 않아서 promise them과 async await의 차이가 거의 느껴지지 않는다.
그렇다면 코드를 늘려 보자.
[promise then 방식]
function printHotels() {
return getHotels()
.then(data => {
if (data.property) {
return sampleFunc1(data)
.then(anotherData => {
console.log(anotherData)
})
}else {
console.log(data)
}
})
}
=> 위 코드는 라인 수도 많고 들여쓰기가 복잡함
[async await 방식(권장) ]
async function printHotels() {
const hotels = await getHotels();
if (hotels.property) {
const sampleData = await sampleFunc1(hotels);
console.log(sampleData);
}else {
console.log(hotels);
}
}
=> then 방식과 비교했을 때 들여쓰기도 간단하고 코드가 간결함.
=> 응답값이 변수에 담기기 때문에 직관적임
2-2. async를 사용하면 에러 핸들링이 쉽다.
- 서버에 데이터를 요청하는 작업을 하다보면, 에러가 발생할 가능성을 염두에 두고 코드를 짜야 한다.
- 에러 핸들링적인 측면에서 async await가 좀 더 유리하다.
- printHotels()에서 에러가 발생한 것이 아니고 JSON.parse에서 에러가 발생했다고 가정함.
- 이 경우, then을 사용하면 catch문을 추가해주어야 한다.
- 즉 catch문이 중복된다.
function printHotels() {
try {
getHotels()
.then((response) => {
const data = JSON.parse(response); // 에러 발생한 부분
console.log(data);
})
.catch((err)=> { // 추가적인 에러
console.log(err)
})
}
catch(err) {
console.log(err)
}
}
async function printHotels() {
try {
const data = await JSON.parse((getHotels())
console.log(data);
}
catch(err) {
console.log(err)
}
}
- 반면 async await를 해 주면 catch문 하나로 try 내부에서 발생하는 모든 에러에 접근 가능함.
2-3. async를 사용하면 어떤 지점에서 에러가 발생했는지 쉽게 찾을 수 있다.
[async await] : 좋은 예시
async function fetchData() {
const response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return await response.json();
}
async function processData() {
try {
const data = await fetchData();
console.log(data);
} catch (error) {
console.error("Error fetching data:", error.message);
}
}
processData();
console.log("This message is logged immediately after processData is called.");
- fetchData 함수는 fetch를 사용하여 데이터를 가져온다.
- await 키워드를 사용하여 비동기 작업이 완료될 때까지 기다린다.
- 응답이 성공적이지 않은 경우(response.ok가 false), 에러를 발생시킴
- processData 함수는 fetchData를 호출하고, try-catch 블록을 사용하여 에러 처리를 해 준다.
- 에러가 발생하면, catch 블록에서 에러 메시지를 출력
위에서 본 것처럼 async await를 써 주면 코드가 동기적으로 작성된 것처럼 보이기 때문에, 에러가 발생했을 때 어느 부분에서 문제가 발생했는지 쉽게 추적가능하다. 예를 들어, fetchData 함수 내에서 에러가 발생하면 processData의 catch 블록에서 이를 잡아 처리하기 때문이다.
[Promise 사용 예제 ] : 나쁜 예시
- 프로미스가 연속적으로 호출되면 어떤 then 지점에서 에러가 발생했는지 찾기가 어렵다.
function fetchData() {
return fetch("https://api.example.com/data")
.then(response => {
if (!response.ok) {
throw new Error(`HTTP error! status: ${response.status}`);
}
return response.json();
});
}
function processData() {
fetchData()
.then(data => {
console.log(data);
})
.catch(error => {
console.error("Error fetching data:", error.message);
});
}
processData();
console.log("This message is logged immediately after processData is called.");
이 예제에서 Promise 체인은 then 블록이 여러 개일 경우 에러가 발생한 위치를 명확히 파악하기 어려울 수 있다.
또 여러 개의 중첩된 비동기 작업이 있을 경우, 콜백 지옥(callback hell)이 발생하여 코드 가독성이 떨어진다.
즉, async를 써 주면 디버그를 할 때 then과 달리 정확한 위치를 지정할 수 있는 장점이 있다.
'프로그래밍언어 > JavaScript' 카테고리의 다른 글
[자바스크립트] 3글자 끝말잇기, DOM객체 연습 (5) | 2024.11.08 |
---|---|
[JavaScript] Windows10 자바스크립트 팝업창이 무한 로딩 / 무한 팝업 될 때 해결법 (12) | 2024.11.07 |
[Javascript] screen, location, history, navigator 객체와 속성 (+메서드) (0) | 2024.04.29 |
[JavaScript] 자바스크립트 브라우저 객체 : alert(), open(), prompt(), confirm(), setTimeout(), setInterval() (0) | 2024.04.23 |
[JavaScript] 소수점 둘째자리에서 반올림 toFixed() , truncateToFixed() 메서드 (1) | 2024.03.29 |

이번 포스팅에서 promise, async await의 차이점을 알아보자!
1. 자바스크립트에서 비동기 처리가 필요한 이유
- js는 동기적인 언어이나 대기시간이 긴 작업(서버에 데이터를 요청하는 작업)을 하는 경우 비동기 작업을 하기도 한다.
- 아래는 비동기 처리가 필요한 간단한 예시이다.
- getHotels()는 서버에서 호텔의 데이터를 받아오는 함수이다.
- 그리고 우리는 getHotels()의 응답값을 받아 출력하고 싶다.
function printHotels() { const hotels = getHotels(); console.log(hotels); }
위와 같이 작성하면 Hotels()의 값이 출력될까?
- 답은 No
- 왜? 자바스크립트는 기본적으로 동기적인 언어이지만, 대기시간 긴 작업의 경우 비동기로 작업하기 때문에 getHotels()보다 콘솔 출력이 먼저 발생하기 때문에 콘솔창에는 undefined가 출력된다.
function printHotels() { const hotels = getHotels(); // 이것봐라? 대기 시간이 너무 기네? console.log(hotels); // 그럼 해당 출력 코드 먼저 실행하자 } printAnimals(); // undefined
- 그렇다면 getHotels()의 응답값(response)를 사용하고 싶다면 어떤 조치를 취해줘야 할까?
- 바로 이 때 비동기 처리방식 promise, async await를 사용해 준다. 그렇다면 이들의 차이점은?
아래는 자바스크립트에서 비동기 처리가 필요한 몇 가지 예시이다.
1. 서버로부터 데이터 가져오기 (AJAX 요청)
2. 파일 읽기/쓰기
3. 타이머 함수 사용
4. Promise와 async/await 사용
1-1. 서버로부터 데이터 가져오기 (AJAX 요청)
웹 애플리케이션에서 서버로부터 데이터를 가져오는 작업은 시간이 오래 걸릴 수 있다. 이 작업을 동기로 처리하면 데이터가 도착할 때까지 다른 모든 작업이 블록된다.
[잘못된 예시]
// 동기적 처리 예시 (나쁜 예시) function fetchDataSync() { var xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.example.com/data", false); // false: 동기적 xhr.send(null); if (xhr.status === 200) { console.log(xhr.responseText); } } fetchDataSync(); console.log("이 메시지는 데이터가 모두 로드된 후에야 출력됩니다."); // 이 메시지는 데이터가 도착한 후에 출력됨
위 코드를 아래처럼 비동기적으로 처리하면 다른 작업이 블록되지 않는다.
[좋은 예시]
// 비동기적 처리 예시 (좋은 예시) function fetchDataAsync() { var xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.example.com/data", true); // true: 비동기적 xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { console.log(xhr.responseText); } }; xhr.send(null); } fetchDataAsync(); console.log("이 메시지는 데이터가 로드되기 전에 출력될 수 있습니다."); // 이 메시지는 즉시 출력됨
1-2. 파일 읽기/쓰기
파일 시스템에 접근하는 작업은 오래 걸릴 수 있다. 이를 비동기적으로 처리하지 않으면 파일 읽기/쓰기 작업이 완료될 때까지 자바스크립트가 멈춘다.
[잘못된 예시]
const fs = require('fs'); // 동기적 파일 읽기 (나쁜 예시) function readFileSync() { const data = fs.readFileSync('/path/to/file', 'utf8'); console.log(data); } readFileSync(); console.log("이 메시지는 파일이 모두 읽힌 후에야 출력됩니다."); // 이 메시지는 파일이 읽힌 후에 출력됨
[좋은 예시]
// 비동기적 파일 읽기 (좋은 예시) function readFileAsync() { fs.readFile('/path/to/file', 'utf8', (err, data) => { if (err) throw err; console.log(data); }); } readFileAsync(); console.log("이 메시지는 파일이 읽히기 전에 출력될 수 있습니다."); // 이 메시지는 즉시 출력됨
1-3. 타이머 함수 사용
타이머 함수(setTimeout, setInterval)는 일정 시간이 지난 후에 특정 작업을 수행해야 할 때 유용하다. (비동기적 작동)
// setTimeout을 사용한 비동기 처리 console.log("이 메시지는 즉시 출력됩니다."); setTimeout(() => { console.log("이 메시지는 2초 후에 출력됩니다."); }, 2000); console.log("이 메시지도 즉시 출력됩니다."); // 이 메시지는 setTimeout 콜백 이전에 출력됨
1-4. Promise와 async/await 사용
비동기 처리를 위해 Promise와 async/await를 사용하면 코드 가독성이 향상됨.
// Promise를 사용한 비동기 처리 function fetchData() { return new Promise((resolve, reject) => { var xhr = new XMLHttpRequest(); xhr.open("GET", "https://api.example.com/data", true); xhr.onreadystatechange = function() { if (xhr.readyState === 4 && xhr.status === 200) { resolve(xhr.responseText); } else if (xhr.readyState === 4) { reject("Error fetching data"); } }; xhr.send(null); }); } fetchData() .then(data => { console.log(data); }) .catch(error => { console.error(error); }); // async/await를 사용한 비동기 처리 async function fetchDataAsync() { try { const data = await fetchData(); console.log(data); } catch (error) { console.error(error); } } fetchDataAsync(); console.log("이 메시지는 fetchDataAsync 호출 후에 즉시 출력됩니다."); // 이 메시지는 즉시 출력됨
2. promise vs async await
2-1. async를 사용하면 코드가 간결하다.
- 앞선 예시 getHotels()를 호출하여 응답값을 받고, 이 응답값을 출력하고자 한다.
- promise의 then방식의 코드는 아래와 같다.
function print Hotels() { getHotels().then((data) => { console.log(data); }) }
- 이 코드를 async await로 바꾸고 싶다. => 함수에 async 키워드를 적고, 비동기 대상에 await를 추가
- 비동기 대상 함수에 await를 추가는 것 => '해당 함수의 처리를 기다려!'
- 그리고 await 함수 아래에 해당 함수의 응답값을 사용하는 구문을 추가해주자.
async function printHotels() { const hotels = await getHotels(); // 해당 함수처리 끝날때까지 기다려! console.log(hotels) // 응답값 출력됨 }
여기까지는 코드가 별로 길지 않아서 promise them과 async await의 차이가 거의 느껴지지 않는다.
그렇다면 코드를 늘려 보자.
[promise then 방식]
function printHotels() { return getHotels() .then(data => { if (data.property) { return sampleFunc1(data) .then(anotherData => { console.log(anotherData) }) }else { console.log(data) } }) }
=> 위 코드는 라인 수도 많고 들여쓰기가 복잡함
[async await 방식(권장) ]
async function printHotels() { const hotels = await getHotels(); if (hotels.property) { const sampleData = await sampleFunc1(hotels); console.log(sampleData); }else { console.log(hotels); } }
=> then 방식과 비교했을 때 들여쓰기도 간단하고 코드가 간결함.
=> 응답값이 변수에 담기기 때문에 직관적임
2-2. async를 사용하면 에러 핸들링이 쉽다.
- 서버에 데이터를 요청하는 작업을 하다보면, 에러가 발생할 가능성을 염두에 두고 코드를 짜야 한다.
- 에러 핸들링적인 측면에서 async await가 좀 더 유리하다.
- printHotels()에서 에러가 발생한 것이 아니고 JSON.parse에서 에러가 발생했다고 가정함.
- 이 경우, then을 사용하면 catch문을 추가해주어야 한다.
- 즉 catch문이 중복된다.
function printHotels() { try { getHotels() .then((response) => { const data = JSON.parse(response); // 에러 발생한 부분 console.log(data); }) .catch((err)=> { // 추가적인 에러 console.log(err) }) } catch(err) { console.log(err) } }
async function printHotels() { try { const data = await JSON.parse((getHotels()) console.log(data); } catch(err) { console.log(err) } }
- 반면 async await를 해 주면 catch문 하나로 try 내부에서 발생하는 모든 에러에 접근 가능함.
2-3. async를 사용하면 어떤 지점에서 에러가 발생했는지 쉽게 찾을 수 있다.
[async await] : 좋은 예시
async function fetchData() { const response = await fetch("https://api.example.com/data"); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } async function processData() { try { const data = await fetchData(); console.log(data); } catch (error) { console.error("Error fetching data:", error.message); } } processData(); console.log("This message is logged immediately after processData is called.");
- fetchData 함수는 fetch를 사용하여 데이터를 가져온다.
- await 키워드를 사용하여 비동기 작업이 완료될 때까지 기다린다.
- 응답이 성공적이지 않은 경우(response.ok가 false), 에러를 발생시킴
- processData 함수는 fetchData를 호출하고, try-catch 블록을 사용하여 에러 처리를 해 준다.
- 에러가 발생하면, catch 블록에서 에러 메시지를 출력
위에서 본 것처럼 async await를 써 주면 코드가 동기적으로 작성된 것처럼 보이기 때문에, 에러가 발생했을 때 어느 부분에서 문제가 발생했는지 쉽게 추적가능하다. 예를 들어, fetchData 함수 내에서 에러가 발생하면 processData의 catch 블록에서 이를 잡아 처리하기 때문이다.
[Promise 사용 예제 ] : 나쁜 예시
- 프로미스가 연속적으로 호출되면 어떤 then 지점에서 에러가 발생했는지 찾기가 어렵다.
function fetchData() { return fetch("https://api.example.com/data") .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }); } function processData() { fetchData() .then(data => { console.log(data); }) .catch(error => { console.error("Error fetching data:", error.message); }); } processData(); console.log("This message is logged immediately after processData is called.");
이 예제에서 Promise 체인은 then 블록이 여러 개일 경우 에러가 발생한 위치를 명확히 파악하기 어려울 수 있다.
또 여러 개의 중첩된 비동기 작업이 있을 경우, 콜백 지옥(callback hell)이 발생하여 코드 가독성이 떨어진다.
즉, async를 써 주면 디버그를 할 때 then과 달리 정확한 위치를 지정할 수 있는 장점이 있다.
'프로그래밍언어 > JavaScript' 카테고리의 다른 글
[자바스크립트] 3글자 끝말잇기, DOM객체 연습 (5) | 2024.11.08 |
---|---|
[JavaScript] Windows10 자바스크립트 팝업창이 무한 로딩 / 무한 팝업 될 때 해결법 (12) | 2024.11.07 |
[Javascript] screen, location, history, navigator 객체와 속성 (+메서드) (0) | 2024.04.29 |
[JavaScript] 자바스크립트 브라우저 객체 : alert(), open(), prompt(), confirm(), setTimeout(), setInterval() (0) | 2024.04.23 |
[JavaScript] 소수점 둘째자리에서 반올림 toFixed() , truncateToFixed() 메서드 (1) | 2024.03.29 |