티스토리 뷰
자바스크립트에서 function(함수)는 object(객체)이다
이름이 없는 함수를 익명함수라고 한다
함수 실행시 조건이 맞지 않으면 바로 종료하도록 빠르게 return을 넣어 짜는 것을 추천
// 비추천
function A (score) {
if (score > 10) {
// 길고 긴 코드
}
};
// 추천
function A (score) {
if (score <= 10) {
return;
}
// 길고 긴 코드
};
자바스크립트는 synchronus(동기적)
> 호이스팅이 된 이후부터 작성한 순서대로 실행됨
하지만 asynchronus(비동기적)인 함수도 있음
> 코드가 언제 실행될지 알 수 없음
예) setTimeout();
비동기의 값은 실패, 성공만 가져옴
내가 요청한 value를 가져오지 않음, value는 콜백함수가 받음
콜백함수 callback function
함수에서 다른 함수를 인자로 전달해서 호출하는 것
function randomQuiz(answer, printYes, printNo) {
if (answer === 'yes') {
printYes();
} else {
printNo();
}
}
const printYes = function () {
console.log('yes');
}
const printNo = function () {
console.log('No');
}
동기적 콜백 / 비동기적 콜백
// Synchronous callback
function printImmediately(print) {
print();
}
printImmediately(() => console.log('hello'));
// Asynchronous callback
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
콜백지옥
함수에서 콜백함수를 호출하고 전달하고 또 그안에서 호출하고 전달하고 하는 것
!문제점
- 가독성이 떨어짐
- 로직을 한눈에 알아보기가 어려움
- 에러가 발생해서 디버깅 해야 할 때도 어려움
- 유지 보수도 어려움
// Callback Hell example
class UserStorage {
loginUser(id, password, onSuccess, onError) {
setTimeout(()=>{
if (
(id === 'user1' && password === 'password1') ||
(id === 'user2' && password === 'password2')
) {
onSuccess(id);
} else {
onError(new Error('not found'));
}
}, 2000);
}
getRoles(user, onSuccess, onError) {
setTimeout(()=>{
if (user === 'user3') {
onSuccess({name: 'bong', role: 'admin'});
} else {
onError(new Error('no access'));
}
}, 1000);
}
}
const UserStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
UserStorage.loginUser(
id,
password,
user => {
UserStorage.getRoles (
user,
userWithRole => {
alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`);
},
error => {
console.log(error);
}
);
},
error => {
console.log(error);
}
)
promise
자바스크립트에 내장된 비동기를 간편하게 처리할 수 있도록 도와주는 오브젝트
콜백함수 대신 유용하게 사용할 수 있음
정해진 기능을 수행하고 정상적으로 작동했다면 성공메세지와 결과값 전달
기능을 수행하다가 문제가 발생하면 에러를 전달
promise 생성
// 1. Producer
const promise = new Promise((resolve, reject) => {
// doing some heavy work ()
});
무거운 작업을 수행할 때 동기적으로 처리하면 작업을 진행하는 동안 코드가 실행이 되지 않으므로
시간이 오래 걸리는 작업은 비동기적으로 처리하는 것이 좋음
예) 네트워크, 파일 읽어오기
promise 안에서 꼭 resolve나 reject로 끝내줘야함
그렇지 않으면 계속 pending 상태로 있음
promise는 생성되는 그 순간 인자로 받은 콜백함수가 실행되므로 주의!
특정행동을 하면 콜백함수가 실행되어야 할 때는 불필요한 작업이 실행될 수 있음!
promise 사용
then이 있으면 콜백 함수가 실행완료가 되는데로 보여줄게! (비동기적 처리)
// 1. Producer
const promise = new Promise((resolve, reject) => {
// doing some heavy work ()
setTimeout(() => {
// resolve('bong');
reject(new Error('no network')); // new Error : 자바스크립트에서 제공하는 객체
}, 2000);
});
// 2. Consumers: then, catch, finally
promise
.then((value) => { // 성공했을 때 호출
console.log(value);
})
.catch((error) => { // 실패했을 때 호출
console.log(error);
})
.finally(() => { // 성공하던 실패하던 마지막으로 실행하고 싶을 때 사용
console.log('finally');
});
Promise chaining
// 3. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num * 2) // 2
.then(num => num * 3) // 6
.then(num => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num - 1), 1000); // 5
});
})
.then(num => console.log(num)); // 5
then은 값을 바로 전달 할 수도 있고 Promise를 전달 할 수도 있음
Error Handling
성공적으로 작동되었을 때
// 4. Error Handling
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐓'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${hen} => 🥚`), 1000);
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
getHen()
.then(hen => getEgg(hen))
.then(egg => cook(egg))
.then(meal => console.log(meal));
이렇게 코드를 줄일 수도 있음
getHen()
.then(getEgg) // 한가지만 받아서 그대로 전달하는 경우 생략 가능
.then(cook)
.then(console.log);
오류가 났을 때!
const getHen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('🐓'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`error! ${hen} => 🥚`)), 1000);
});
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} => 🍳`), 1000);
});
getHen()
.then(getEgg)
.catch(error => { // 받아오면서 오류가 났을 때 체인 전체가 실패하지 않도록 에러를 처리해주기
return '🥖';
})
.then(cook)
.then(console.log)
.catch(console.log);
중간에 오류가 날 경우를 대비하여 에러를 처리해주는게 좋음
처리해주면 return된 값을 넣어서 결과가 출력되지만
처리하지 않으면 출력된 결과는 에러가 나옴
위의 콜백지옥을 promise를 사용하여 더 좋게 바꿀 수 있음
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === 'ellie' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
resolve(id);
} else {
reject(new Error('not found'));
}
}, 2000);
});
}
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === 'ellie') {
resolve({ name: 'ellie', role: 'admin' });
} else {
reject(new Error('no access'));
}
}, 1000);
});
}
}
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
userStorage
.loginUser(id, password)
.then(userStorage.getRoles)
.then(user => alert(`Hello ${user.name}, you have a ${user.role} role`))
.catch(console.log);
async / await
기존의 promise 위에 좀 더 API가 추가된 것 (syntactic sugar)
그렇다고 무조건 promise보다 async / await 이 좋은 것은 아님! 경우에 따라 더 적합한 것을 사용하면 됨
async 사용
함수 앞에 async를 적으면 promise로 바로 만들 수 있음
// 1. async
async function fetchUser() { // 자동으로 promise로 바뀜
// 10초 정도 걸리는 네트워크
return 'user name';
}
const user = fetchUser();
user.then(console.log);
console.log(user);
await 사용
async가 사용된 함수 안에서만 사용 가능
await이 적힌 함수가 끝날 때까지 기다리도록 함 > 동기적으로 적은 코드처럼 가독성이 더 높아짐
// 2. await
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(3000); // delay함수가 끝날 때 까지 기다려라
return '🍎';
}
async function getBanana() {
await delay(3000);
return '🍌';
}
promise도 너무 중첩하면 콜백지옥처럼 됨
function pickFruits() {
return getApple()
.then(apple => {
return getBanana()
.then(getBanana => `${apple} 와(과) ${banana}`);
});
}
pickFruits().then(console.log);
async를 사용해서 간단히 써 줄 수 있음
동기적으로 적은 코드처럼 적어줄 수 있음
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} 와(과) ${banana}`;
}
pickFruits().then(console.log);
await 동기화
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(3000);
return '🍎';
}
async function getBanana() {
await delay(3000);
return '🍌';
}
async function pickFruits() {
const apple = await getApple(); // 3초
const banana = await getBanana(); // 3초
return `${apple} 와(과) ${banana}`; // 6초나 걸림
}
pickFruits().then(console.log);
이렇게 적으면 await 때문에 차례대로 실행하기 때문에 return을 하는데까지 6초가 걸림
> 값을 따로따로 받아오는데 굳이 기다리는 것은 비효율적
async function pickFruits() {
const applePromise = getApple(); // apple promise 생성
const bananaPromise = getBanana(); // banana promise 생성
const apple = await applePromise(); // 동기화
const banana = await bananaPromise(); // 동기화
return `${apple} 와(과) ${banana}`; // 3초가 걸림
}
pickFruits().then(console.log);
promise는 생성되는 순간 내장 함수를 바로 실행하기 때문에 promise와 await을 동기화를 해줘서
굳이 기다릴 필요 없이 사과와 바나나를 한번에 출력할 수 있음
하지만 값을 받아오는데 연관이 없는 병렬적인 promise는 저렇게 길게 쓸 필요 없음
값을 받아오는데 연관이 없이 병렬적일 때는 Promise.all 사용
function promiseAll() {
return Promise.all([Promise1(), Promise2()]) // 받아온 배열의 Promise들을 모두 병렬적으로 실행
.then(() => {}) // 받아진 배열을 전달, 모두 받아온 뒤에 실행
}
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(3000);
return '🍎';
}
async function getBanana() {
await delay(3000);
return '🍌';
}
function pickAllFruits() {
return Promise.all([getApple(), getBanana()])
.then(fruits => fruits.join('와(과)'));
}
pickAllFruits().then(console.log); // 사과와 바나나 동시에 출력
제일 먼저 끝나는 Promise 하나만 받고 싶다!
Promise.race 사용
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(3000);
return '🍎';
}
async function getBanana() {
await delay(1000);
return '🍌';
}
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()]);
}
pickOnlyOne().then(console.log); // 바나나 출력
async 에러 처리
throw
async function getApple() {
await delay(3000);
throw 'error'; // 이렇게하면 에러가 발생
return '🍎';
}
try / catch
async function pickFruits() {
try {
const apple = await getApple();
const banana = await getBanana();
return `${apple} 와(과) ${banana}`;
} catch() {
// 에러 처리
}
}
'공부 노트' 카테고리의 다른 글
화살표함수 arrow function (0) | 2021.12.11 |
---|---|
map(), filter() (0) | 2021.12.11 |
재귀 함수 (0) | 2021.12.06 |
시맨틱 태그(Semantic tag) (0) | 2021.09.27 |
메뉴를 만들 때 <li>를 사용하는 이유 (0) | 2021.09.23 |
- Total
- Today
- Yesterday
- 구름에듀
- 제로초
- vue
- CSS
- map
- js
- 깃
- 스파르타코딩클럽
- 제이쿼리
- 저스트코드
- 김버그
- scss
- 코딩앙마
- Til
- Typescript
- Python
- git
- 타입스크립트
- javascript
- html
- TS
- 자바스크립트
- 코드잇
- vscode
- 드림코딩
- 파이썬
- 리액트
- 회고
- React
- 비주얼스튜디오코드
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |