console.log(1);
console.log(2);
console.log(3);
/**
* 1
* 2
* 3
*/
console.log(1);
setTimeout(() => {
console.log(2);
}, 1000);
console.log(3);
/**
* 1
* 3
* 2
*/
btnEl
은 버튼이 눌렸을 때 동작하므로 정확하게 언제 실행될지 모름 → 비동기 방식으로 동작
const btnEl = document.querySelector('h1');
btnEl.addEventListener("click", () => {
console.log("Clicked");
});
console.log("Hello World!");
먼저 작성한 코드는 fetch()
함수이지만, 1, 2, 3이 먼저 출력됨
fetch(url)
.then(res => res.json())
.then(res => console.log(res));
console.log(1);
console.log(2);
console.log(3);
/**
* 1
* 3
* 2
* 특정 데이터
*/
fetch()
: 특정한 웹 주소로 데이터를 전송할 때 사용
→ 요청(request), 응답(response)
인터넷 응답 속도에 따라 출력되는 시간이 달라짐
JS에서 비동기 코드는 실행하자마자 응답값이 도착하지 않아도 다음 코드로 넘어감
응답값을 받은 후 코드 실행하는 방법
fetch(url)
.then(res => res.json())
.then(res => {
console.log(res);
console.log(1);
console.log(2);
console.log(3);
});
/**
* 특정 데이터
* 1
* 3
* 2
*/
const a = () => console.log(1);
const b = () => console.log(2);
a();
b();
/**
* 1
* 2
*/
const a = (callback) => {
setTimeout(() => {
console.log(1);
callback();
}, 1000);
};
const b = () => console.log(2);
a();
b();
/**
* 2
* 1
*/
❗️ 비동기 방식에서 실행 순서를 보장하기 위해 콜백 패턴 사용
콜백 패턴 장점: 순서 보장 가능
콜백 패턴 단점: 들여쓰기가 점점 깊어짐 → 콜백 지옥
Promise
와 async/await
사용!ex) 영화 정보 검색
const getMovies = (movieName, callback) => {
fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=${movieName}`)
.then((response) => response.json())
.then((res) => {
console.log(res);
callback();
});
};
getMovies("frozen", () => {
console.log("겨울왕국");
getMovies("avengers", () => {
console.log("어벤져스");
getMovies("avatar", () => {
console.log("아바타");
});
});
});
콜백 지옥을 해결해주는 클래스
Promise 클래스를 이용하여 메소드 체이닝을 통해 비동기 함수를 순차적으로 실행
new Promise((resolve) => resolve());
resolve
매개변수는 Promise 객체의 then 메소드 호출했을 때 콜백 함수 실행const a = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(1);
resolve(); // 위의 코드가 실행된 후에 resolve()가 실행됨 -> 실행 위치 보장
}, 1000);
});
};
const b = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(1);
resolve(); // 위의 코드가 실행된 후에 resolve()가 실행됨 -> 실행 위치 보장
}, 1000);
});
};
const c = () => {
return new Promise((resolve) => {
setTimeout(() => {
console.log(1);
resolve(); // 위의 코드가 실행된 후에 resolve()가 실행됨 -> 실행 위치 보장
}, 1000);
});
};
const d = () => console.log(4);
a()
.then(() => {
return b();
})
.then(() => {
return c();
})
.then(() => {
return d();
});
resolve
는 하나의 함수 데이터를 받음// 아래와 같은 형태로 작성 가능
a()
.then(b)
.then(c)
.then(d)
.then(() => console.log("done"));
ex) 영화 정보 검색을 Promise 사용하여 작성
const getMovies = movieName => {
return new Promise(resolve => {
fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=${movieName}`)
.then(response => response.json())
.then(res => {
console.log(res);
resolve();
});
});
}
getMovies("frozen")
.then(() => {
console.log("겨울왕국");
return getMovies("avengers");
})
.then(() => {
console.log("어벤져스");
return getMovies("avatar");
})
.then(() => {
console.log("아바타");
});
await
: 그 뒤쪽에 있는 비동기 함수의 실행을 기다린다는 의미
const a = () => {
return new Promise(resolve => {
setTimeout(() => {
console.log(1);
resolve();
}, 1000);
});
};
const b = () => console.log(2);
const wrap = async () => {
await a();
b();
};
wrap();
ex) 영화 정보 검색을 async/await
사용하기
const getMovies = (movieName) => {
return new Promise((resolve) => {
fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=${movieName}`)
.then((response) => response.json())
.then((res) => {
console.log(res);
resolve();
});
});
};
const wrap = async () => {
await getMovies('frozen');
console.log('겨울왕국');
await getMovies("avengers");
console.log("어벤져스");
await getMovies("avatar");
console.log("아바타");
wrap();
에러를 처리하는 것
1. 콜백함수를 통한 처리
const delayAdd = (index, cb, errorCb) => {
setTimeout(() => {
if(index > 10) {
errorCb(`${index}는 10보다 클 수 없다.`);
return;
}
console.log(index);
cb(index+1);
}, 1000);
};
delayAdd(4, (res) => console.log(res), (err) => console.error(err));
/*
* 4
* 5
*/
2. Promise의 resolve, reject를 통한 처리
resolve
: 정상적으로 로직이 동작하면 콜백함수를 통해 결과 전달reject
: 에러가 발생하면 에러 전달then().catch()
를 통해 에러 핸들링then
메소드에 있는 콜백함수는 resolve의 매개변수로 들어감catch
메소드에 있는 콜백함수는 reject의 매개변수로 들어감const delayAdd = (index) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(index > 10) {
reject(`${index}는 10보다 클 수 없습니다.`);
return;
}
console.log(index);
resolve(index+1);
}, 1000);
});
};
delayAdd(4)
.then((res) => console.log(res))
.catch((err) => console.log(err));
then().catch().finally()
를 통해 에러 핸들링 가능delayAdd(4)
// then 메소드에 있는 콜백함수는 resolve의 매개변수로 들어감
.then((res) => console.log(res))
// catch 메소드에 있는 콜백함수는 reject의 매개변수로 들어감
.catch((err) => console.error(err))
.finally(() => console.log("Done"));
3. async/await를 통한 처리
try/catch
를 통해 에러 핸들링
const wrap = async () => {
try {
const res = await delayAdd(2);
console.log(res);
} catch (err) {
console.error(err);
}
};
wrap();
try/catch/finally
const wrap = async () => {
try {
const res = await delayAdd(2);
console.log(res);
} catch (err) {
console.error(err);
} finally {
console.log("Done");
}
};
wrap();
ex) 영화 정보 검색 에러 핸들링
const getMovies = (movieName) => {
return new Promise((resolve, reject) => {
fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=${movieName}`)
.then((res) => res.json())
// catch로 걸러지지 않는 실질적인 에러를 처리하기 위해 if문을 통해 에러를 처리
.then((json) => {
if (json.Response === "False") {
reject(json.Error);
}
resolve(json);
})
.catch((error) => {
reject(error);
});
});
};
let loading = true;
then/catch/finally
구문 → .then()
delayAdd(4)
// then 메소드에 있는 콜백함수는 resolve의 매개변수로 들어감
.then((res) => console.log(res))
// catch 메소드에 있는 콜백함수는 reject의 매개변수로 들어감
.catch((err) => console.error(err))
.finally(() => console.log("Done"));
try/catch/finally
구문 → async/await
const wrap = async () => {
try {
const movies = await getMovies("avengers");
console.log("영화 목록: ", movies);
} catch (error) {
console.log("에러 발생: ", error);
} finally {
loading = false;
}
};
const getMovies = (movieName) => {
return new Promise((resolve) => {
fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=${movieName}`)
.then((res) => res.json())
.then((res) => resolve(res));
});
};
const titles = ["frozen", "avengers", "avatar"];
const wrap = async () => {
for (const title of titles) {
const movies = await getMovies(title);
console.log(title, movies);
}
};
wrap();
forEach
문 이용 → 반복을 매번 기다리면서 사용하는 경우에는 forEach
사용하면 안됨titles.forEach(async (title) => {
const movies = await getMovies(title);
console.log(title, movies);
});
const wrap = async () => {
for (const title of titles) {
const movies = await getMovies(title);
console.log(title, movies);
}
};
wrap();
fetch(주소, 옵션)
네트워크를 통해 리소스의 요청(Request) 및 응답(Response)를 처리
→ Promise 인스턴스 반환
fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=frozen`)
.then((res) => console.log(res.json()))
.then((json) => console.log(json));
async/await
구문const wrap = async () => {
const res = await fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=frozen`);
const json = await res.json();
console.log(json);
};
wrap();
→ 요청에 필요한 옵션 전달
GET
, POST
, PUT
, DELETE
Content-Type: application/json
: 서버로 전송되는 타입이 무엇인지 명시JSON.stringify()
)fetch(`https://www.omdbapi.com/?apikey=7035c60c&s=frozen`, {
method: `GET`,
headers: {
"Content-Type": "application/json",
},e
body: {
name: "HEROPY",
age: 85,
},
})
.then((res) => res.json())
.then((json) => console.log(json));