TIL
1.call back
call back은 Synchronous, Asynchronous 모두 가능하다.
// 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);
call back을 잘못 사용하면 function이 다른 function을 불러내고 또 몇 초 뒤에 다른 function을 불러내게 되는데 너무 많은 콜백을 사용할 경우 가독성이 떨어지고 디버깅이 어려워진다.
2.Promise
Promise는 JS에서 Async 처리를 Sync로 처리할 수 있게 돕는 객체 유형이다. Promise는 반드시 3가지 상태를 지니는데, 대기(Pending) 상태가 아니라면 Promise의 연산이 이미 끝난 상태(Fulfilled, Rejected) 로 볼 수 있다.
1. Producer side
const timerpromise = new Promise((resolve, reject)=>{
// executor가 Promise라는 object 만들어지자마자 바로 실행된다.
// 여기에 resolve쓰면 output: middle, last, first 순서
// resolve()
setTimeout(()=>{
// executor에는 함수만 올 수 있으며 parameter로 resolve, reject가 pass된다.
resolve();
console.log('First');
// resolve();
// resolve();
// 직접 reject를 실행하면 promise에서 에러가 발생한 것으로 간주
// reject('Error!');
}, 1000)
});
2. Consumer side: then, catch, finally
timerpromise
// resolve함수가 호출되기 전까지 코드 실행 안됨.
.then(()=>{
console.log('Middle');
console.log('Last');
})
.catch((error)=>{
console.log('에러 발생!', error);
// finally는 실패(catch), 성공(then)과 상관없이 항상 실행된다.
// 실패, 성공과 상관없이 어떤 기능을 마지막으로 수행하고 싶을 떄 사용
.finally(
console.log('finally');
});
a) Promise가 만들어 질 때 executor가 자동적으로 바로 실행되기 때문에, 병렬적으로 동작을 하기 위함이 목적이라면 빠른 시간 내에 정보를 처리할 수 있겠지만, 만약 promise 안에 네트워크 통신을 하는 코드를 집어넣었다면 promise가 만들어지는 순간 네트워크가 실행되기 때문에 사용자가 요구했을 때만 네트워크 요청을 하려고 한다면 promise는 주의를 기울여서 사용해야 한다.
b) Promise에서 then을 호출하게 되면 다시 promise가 return이 되고 return된 Promise에 catch를 등록, catch에서 다시 promise가 return 되고 그 promise에 finally가 등록된다.
3.Async & Await
function fetchUser(){
return new Promise((resolve, reject)=>{
// do network request in 10 secs...
resolve('Ellie');
});
}
Async function fetchUser(){
// do network request in 10 secs...
resolve('Ellie');
});
}
const user = fetchUser();
user.then(console.log);
console.log(user);
Async라는 Keyword를 function 앞에 사용하면 번거롭게 promise를 사용하지 않아도 자동적으로 함수 안에 있는 코드 블럭들이 Promise로 변환이 되어진다.
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
function getApple(){
return delay(3000)
.then(()=> 'apple!');
}
// 위의 코드를 async를 사용해서 간소화
async function getApple(){
await delay(3000);
return 'apple!';
async function getBanana(){
await delay(3000);
return 'banana!';
async function pickFruits(){
try{
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`;
} catch(){
Error
}
pickFruits().then(console.log);
Await라는 keyword를 사용하게 되면 delay가 끝날 때까지 기다려준다. 단, async 내에서만 await 사용이 가능하다.
async function getApple(){
await delay(3000);
return 'apple!';
async function getBanana(){
await delay(3000);
return 'banana!';
async function pickFruits(){
try{
const apple = await getApple();
// getApple()이 끝날 때까지 3초 기다려야 하기 때문에 비효율적
const banana = await getBanana();
return `${apple} + ${banana}`;
} catch(){
Error
}
async function pickFruits(){
try{
// await을 빼면 getApple, 즉 promise의 executor가 바로 실행되게 된다.
// getApple, getBanana가 병렬적으로 동작 가능
const applePromise = getApple();
const bananaPromise = getBanana();
cont apple = await applePromise;
cont banana = await bananaPromise;
return `${apple} + ${banana}`;
} catch(){
Error
}
prickFruits().then(console.log);
병렬적으로 기능을 수행하는 경우에는 await을 제거하면 promise의 executor가 바로 실행될 수 있다. 이를 더 간단하게 나타내기 위해서는 Promise에 있는 all API를 사용하면 된다.
3. useful Promise APIs
function pickAllFruits(){
return Promise.all([getApple(), getBanana()])
.then(fruits => fruits.join('+')
);
}