<자바스크립트 웹 개발 기본기>
4. async/await을 활용한 세련된 비동기 코드
async/await이란?
promise 객체가 등장함으로써 콜백 헬을 해결할 수 있게됨
→ 이후에도 발전되어 async/await을 사용하게 됨
async funtion fetchAndPrint(){
const response = await fetch('https://jsonplaceholder.typicode.com/users');
const result = await response.text();
console.log(result);
}
fetchAndPrint();
asynchronous 의 줄임말을 사용 (비동기를 의미한다)
await : 뒤에 코드를 실행하고 코드가 리턴하는 promise 객체를 기다린다
fulfilled 상태가 되면 작업 성공결과 추출해서 리턴
async/await 구문의 실행 원리
await 코드는 async 함수 안에서만 사용할 수 있다
async function fetchAndPrint(){
console.log(2);
const response = await fetch('<https://jsonplaceholder.typicode.com/users>');
console.log(7);
const result = await response.text();
console.log(result);
}
console.log(1);
fetchAndPrint();
console.log(3);
console.log(4);
console.log(5);
console.log(6);
- console.log(1) 실행되면서 1이 먼저 출력된다
- fetchAndPrint 함수 안에서 2가 출력된다
- await을 만나면 뒤의 코드를 실행하고 코드의 실행흐름은 fetchAndPrint 함수 뒤로 바뀐다
- 3 4 5 6 이 출력된다
- fulfillled가 실행되면 7이 실행된다
- 그 다음 await에서 fulfiled가 될 때까지 기다린다음 그다음 코드 result가 출력된다
세련된 비동기 실행 코드 작성해보기
async function getTheLastPostOfTheLastUser() {
const usersJSON = await fetch("<https://jsonplaceholder.typicode.com/users>");
const users = await usersJSON.json();
const lastUser = users[users.length - 1];
const { id } = lastUser;
const postsJSON = await fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`);
const posts = await postsJSON.json();
const lastPost = posts[posts.length - 1];
return lastPost;
}
getTheLastPostOfTheLastUser().then((lastPost) => {
console.log(lastPost);
});
----- 수정전
fetch("<https://jsonplaceholder.typicode.com/users>")
.then((response) => response.json())
.then((users) => {
const lastUser = users[users.length - 1];
return lastUser.id;
})
.then((id) => fetch(`https://jsonplaceholder.typicode.com/posts?userId=${id}`))
.then((response) => response.json())
.then((posts) => {
const lastPost = posts[posts.length - 1];
console.log(lastPost);
});
promise 객체가 rejected 상태가 되는 경우 async 사용법
→ try catch문을 사용한다
async function fetchAndPrint(){
try{
const response = await fetch('<https://jsonplaceholder.typicode.comm/users>');
const result = await response.text();
console.log(result);
}catch(error){
console.log(error);
}
}
fetchAndPrint();
☑️실행결과
async/await 퀴즈
async function test1() {
const result = await Promise.resolve('success');
console.log(result);
}
async function test2() {
try {
const p = new Promise((resolve, reject) => {
setTimeout(() => { resolve('last'); }, 3000);
});
const result = await p;
console.log(result);
} catch (e) {
console.log(e);
}
}
async function test3() {
try {
const result = await Promise.reject('fail');
console.log(result);
} catch (e) {
console.log(e);
}
}
test1();
console.log('JavaScript');
test2();
console.log('Programming');
test3();
그 fulfilled 상태를 확인하지 못한 여러 Promise 객체들은 나중에 그것이 fulfilled 또는 rejected 상태가 된 순서대로 그 await 문이 작업 성공 결과를 추출하거나 catch 문으로 실행 흐름이 옮겨진다고 생각하면 된다
setTimeout 함수를 호출해서 가장 늦게 그 상태가 fulfilled로 확정되는 p 객체의 작업 성공 결과인 문자열 last가 가장 마지막에 출력되는 것
try, catch, finally문의 위치
async function showQuiz() {
try {
const response = await fetch('<https://learn.codeit.kr/api/quiz>');
const test = await response.json();
const yourAnswer = prompt(test.quiz);
if (yourAnswer.toLowerCase() === test.answer) {
alert(`Good Job, ${test.explanation} => Let\\'s learn more with Codeit!`);
} else {
throw new Error('wrong');
}
} catch (error) {
if (error.message === 'wrong') {
alert('You need to learn JavaScript with Codeit!');
} else {
alert('Error');
}
} finally {
window.open('<https://codeit.kr>', '_blank');
}
}
showQuiz();
async 함수는 Promise 객체를 리턴
async가 붙은 함수는 늘 promise 객체를 리턴한다
동일한 작업 성공결과를 가진 promise 객체가 리턴된다
→ then 메소드가 리턴한 프로미스 객체를 그대로 리턴함
async 함수가 리턴하는 Promise 객체
1. 어떤 값을 리턴하는 경우
1)promise 객체를 리턴하는 경우
async 함수 안에서 Promise 객체를 리턴하는 경우에는 해당 Promise 객체와 동일한 상태와 작업 성공 결과(또는 작업 실패 정보)를 가진 Promise 객체
2) Promise 객체 이외의 값을 리턴하는 경우
fulfilled 상태이면서, 리턴된 값을 작업 성공 결과로 가진 Promise 객체를 리턴
2. 아무 값도 리턴하지 않는 경우
fulfilled 상태이면서, undefined를 작업 성공 결과로 가진 Promise 객체가 리턴
3. async 함수 내부에서 에러가 발생했을 때 async 함수 안에서 에러가 발생하면, rejected 상태이면서, 해당 에러 객체를 작업 실패 정보로 가진 Promise 객체가 리턴
async 함수 안의 async 함수
const applyPrivacyRule = async function (users){
const resultWithRuleApplied = users.map((user)=>{
const keys=Object.keys(user);
const userWithoutPrivateInfo={};
keys.forEach((key)=>{
if (key!=='address'&& key!=='phone'){
userWithoutPrivateInfo[key]=user[key];
}
});
return userWithoutPrivateInfo;
});
const p = new Promise((resolve, reject)=>{
setTimeout(()=>{resolve(resultWithRuleApplied);},2000);
});
return p;//promise 객체 리턴
};
async function getUsers(){
try {
const response = await fetch('<https://jsonplaceholder.typicode.com/users>');
const result = await response. text();
const users = JSON.parse(result);
const resultWithPrivacyRuleApplied = await applyPrivacyRule(users);
return resultWithPrivacyRuleApplied;
} catch (error) {
console.log(error);
} finally {
console.log('exit');
}
}
getUsers().then((result)=>{console.log(result);});
실행결과
async를 붙이는 위치
자바스크립트에서 함수를 표현하는 방법에는 여러 가지가 있는데요.
- Function Declaration(함수 선언식),
- Function Expression(함수 표현식),
2-1. 함수에 이름이 붙어있는 Named Function Expression과 2-2. 함수에 이름이 없는 Anonymous Function Expression
- Arrow Function(화살표 함수)
// 1) Function Declaration
async function example1(a, b) {
return a + b;
}
// 2-1) Function Expression(Named)
const example2_1= async function add(a, b) {
return a + b;
};
// 2-2) Function Expression(Anonymous)
const example2_2 = async function(a, b) {
return a + b;
};
// 3-1) Arrow Function
const example3_1 = async (a, b) => {
return a + b;
};
// 3-2) Arrow Function(shortened)
const example3_2 = async (a, b) => a + b;
개선된 점심 메뉴 랜덤 선택기 코드
async function pick(menus) {
console.log('Pick random menu!');
const p = new Promise((resolve, reject) => {
if (menus.length === 0) {
reject(new Error('Need Candidates'));
} else {
setTimeout(() => {
const randomIdx = Math.floor(Math.random() * menus.length);
const selectedMenu = menus[randomIdx];
resolve(selectedMenu);
}, 1000);
}
});
return p;
}
async function getRandomMenu() {
console.log('---Please wait!---');
try {
const response = await fetch('<https://learn.codeit.kr/api/menus>');
const menus = await response.json();
const menu = await pick(menus);
console.log(`Today's lunch is ${menu.name}~`);
} catch (error) {
console.log(error.message);
} finally {
console.log('Random Menu candidates change everyday');
}
}
getRandomMenu();
async 함수를 작성할 때 주의해야할 성능 문제(심화)
async function getResponses(urls) {
for(const url of urls){
const response = await fetch(url);
console.log(await response.text());
}
}
바로 이전 URL에 리퀘스트를 보내고 리스폰스를 받아서 출력하고 나서야, 다음 URL에 대한 리퀘스트를 보낼 수 있다는 점. 즉, 순차적인 작업 처리를 한다는 점
리스폰스의 내용의 순서가 중요하지 않은 경우
async function fetchUrls(urls){
for(const url of urls){
(async () => { // 추가된 부분!
const response = await fetch(url);
console.log(await response.text());
})(); // 추가된 부분!
}
}
URL 에 리퀘스트를 보내고 리스폰스를 받는 코드를, 별도의 즉시실행되는 async 함수로 감싼다 (즉시실행함수는 정의와 동시에 실행되는 함수)
URL에 대해서 fetch 함수를 실행해서 리퀘스트를 보내는 것을 순서대로 바로 실행한다( 이전 코드처럼 이전 URL에 대한 리스폰스가 오기까지를 기다렸다가 다음 URL에 리퀘스트를 보내는 게 아니라)
비동기 실행 관련 문법 총정리
- 특정 작업이 시작되고, 그 작업이 모두 완료되기 전에 바로 다음 코드가 실행되는 방식의 실행, 나머지 작업은 나중에 콜백을 통해 수행되는 방식의 실행
- 특정 처리를 나중으로 미루는 방식의 실행
- 콜백을 등록해두고, 추후에 특정 조건이 만족되면 그 콜백으로 나머지 작업을 수행하는 방식의 실행
☑️파라미터로 바로 콜백을 전달하는 형태의 전통적인 비동기 실행 함수
setTimeout, setInterval 함수, DOM 객체의 addEventListener 메소드
☑️Promise
☑️async / await 구문
'🏃♀️ 대외활동 > Codeit Boost-Node.js' 카테고리의 다른 글
6주차 스터디 자바스크립트 백엔드 개발 (2) [코드잇 부스트 백엔드 스터디] (1) | 2024.06.30 |
---|---|
6주차 스터디 자바스크립트 백엔드 개발 (1) [코드잇 부스트 백엔드 스터디] (0) | 2024.06.28 |
5주차 스터디 자바스크립트 웹 개발 기본기 (3) 비동기 실행과 Promise 객체 [코드잇 부스트 백엔드 스터디 ] (2) | 2024.06.04 |
5주차 스터디 자바스크립트 웹 개발 기본기 (2) Web API [코드잇 부스트 백엔드 스터디 ] (1) | 2024.06.04 |
5주차 스터디 자바스크립트 웹 개발 기본기 (1) 웹 기초 [코드잇 부스트 백엔드 스터디 ] (2) | 2024.06.04 |