기술면접_JavaScript_10
프론트엔드 개발자 입문 | JSON Contents JSON파일이란? 파일변환 드림코딩 유투브 채널의 J...
synchronous
console.log("1st");
console.log("2nd");
console.log("3rd");
//출력결과: 1st,2nd,3rd
asynchronous
console.log("1st");
setTimeout(()=>{
console.log("2nd");
},1000)
console.log("3rd");
//출력결과: 1st,3rd,2nd
//위 코드는 동기언이인 JavaScript를 비동기적으로 처리한 것
다른 함수에 매개변수로 넘겨준 함수로, 넘겨받은 함수는 때가 되면 나중에 호출
//setTimeout은 콜백함수로 실행되며 지금 당장 실행되지 않고 필요한 때에 callback(호출)하여 사용
setTimeout(function(){
console.log('1초 후 실행되는 코드')
}, 1000)
//콜백함수는 anonymous로 Arrow function을 통해 표기가능
setTimeout(() => console.log('1초 후 실행되는 코드'), 1000)
정의 : 콜백함수를 반복사용하여 코드의 들여쓰기 수준이 감당하기 힘들 정도로 깊어지는 현상. 여기서 반복사용은 하나의 콜백함수 안에서 계속해서 콜백을 반복하는 것을 말함.
문제 : 코드의 가독성이 떨어지며 오류 디버깅이 어려움
class UserStorage {
//사용자 데이터를 서버에서 받아오는 코드
loginUser(id, password, onSucess, onError) {
setTimeout(() => {
if (
(id === 'ellie' && password == 'dream') ||
(id === 'coder' && password == 'academy')
) {
onSucess(id);
} else {
onError(new Erorr('not found'));
}
}, 2000);
}
//사용자의 역할(ex.손님,정회원)을 서버에서 받아오는 코드
getRoles(user, onSucess, onError){
setTimeout(() => {
if (user === 'ellie') {
onSucess({ name: 'ellie', role: 'admin' });
} else {
onError(new Error('no access'));
}
}, 1000);
}
}
/*---------------------------------------------------------*/
const userStorage = new UserStorage(); //userStorage class delaration
const id = prompt('enter your id');
const password = prompt('enter your password');
//userStorage 사용하여 로그인
userStorage.loginUser(
id,
password,
user => { //1st Callback
userStorage.getRoles(
user,
userWithRole => { //2nd Callback
alert(
`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
);
},
error => { //3rd Callback
console.log(error);
}
);
},
error => { //4th Callback
console.log(error);
}
);
Promise State
프로세스가 기능을 수행중인지 혹은 수행을 성공(실패)하였는지에 대한 상태
Producer vs Consumer
producer : 데이터 제공자 (원하는 기능을 수행하여 해당하는 데이터 생성)
const promise = new Promise((resolve, reject) => {
// doing some heavy work(ex.서버에서 데이터를 받아오는 등의 작업을 말하며, 이를 동기적으로 실행할 경우 비효율적이므로 Promise를 사용하여 비동기적으로 실행하도록 함)
console.log('doing something...');
//1. Wizaed of Oz: 실제 서버를 이용하는 것과 같은 효과를 주기위해 setTimeout사용
//2. resolve or reject사용
serTimeout(() => {
resolve('ellie') //기능수행에 성공할 경우 출력
},2000);
setTimeout(() => {
reject(new Error('no network')) //기능수행에 실패할 경우 출력
},2000);
});
consumer : 데이터 사용자 (원하는 데이터 소비)
promise
//then: 성공할 경우, value(resolve에서 정의)에서 값을 받아와 출력
.then((value) => {
console.log(value);
})
//catch: 실패할 경우, 오류메세지 출력
.catch(error => {
console.log(error);
})
//finally: 성공,실패 여부와 무관하게 출력
.finally(() => {
console.log('finally');
})
Promise chaining
It allows you to chain on another then call which will run when the second promise is fulfilled
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num * 2)
.then(num => console.log(num));
Promise chaining error handling
//Producer
const gethen = () =>
new Promise((resolve, reject) => {
setTimeout(() => resolve('hen'), 1000)
})
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error (`error! ${hen} -> egg`)), 1000)
})
const cook = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} -> fired egg`), 1000)
})
//Consumer
gethen()
.then(getEgg)
.catch(error => {
return 'alternate';
})
.then(egg => cook(egg))
.then(meal => console.log(meal))
.catch(console.log);
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 Erorr('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) //userStorage에 id,pw전달
.then(userStorage.getRoles) //loginUser에서 resolve일 경우, user를 받아와서 getRoles호출
//위 코드의 경우, user= > 생략: 콜백함수 전달 시, 받아오는 value를 통해 다른함수를 바로 호출하는 경우, 생략가능
.then(user => alert(`Hello ${user.name}, you have a ${user.role} role`))
.catch(console.log);
/*1. async*/
//사용자의 데이터를 받아오는 코드(동기처리): 데이터가 받아와지는 동안 다른 코드를 실행할 수 없음
function fetchUser() {
return 'ellie';
}
const user = fetchUser();
console.log(user);
//사용자의 데이터를 받아오는 코드(비동기처리_async): async를 function앞에 작성하면 자동으로 블럭이 Promise로 변경됨
async function fetchUser() {
return 'ellie';
}
const user = fetchUser();
console.log(user);
/*2. await*/
//await사용 시, delay를 통해 비동기처리를 동기처리 코드와 같이 작성할 수 있음
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(1000)
return 'apple';
}
async function getBanana() {
await delay(1000)
return 'banana';
}
async function pickFruits() {
const apple = await getApple();
const banana = await getBanana();
return `${apple} + ${banana}`
}
pickFruits().then(console.log);
/*3. await의 직렬처리 문제*/
//아래 코드를 예시로 보았을 때, getApple과 getBanana function이 순차적으로 진행됨 (사과와 바나나는 서로 연관이 없으므로 이를 순차적으로 실행하는 것은 비효율적)
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getApple() {
await delay(1000)
return 'apple';
}
async function getBanana() {
await delay(1000)
return 'banana';
}
//1번 방법(Promise사용): Promise는 생성과 동시에 실행됨으로 getApple과 getBanana를 병렬처리 할 수 있음
async function pickFruits() {
const applePromise = getApple();
const bananaPromise = getBanana();
const apple = await applePromise;
const banana = await bananaPromise;
return `${apple} + ${banana}`
}
//2번 방법(Promise all APIs사용): Promise배열 전달 시, 모든 Promise가 병렬적으로 다 받아질 때 까지 모아줌
function pickFruits() {
return Promise.all([getApple(), getBanana()]) //Promise가 전부 받아지면
.then(fruits => fruits.join(' + ')); //배열의 값을 join()을 통해 string으로 병합
}
pickFruits().then(console.log);
//Appendix
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()]); //race: 배열에 전달 된 Promise중, 가장 먼저 값이 들어온 것만 return
}
Avenco comes with a built-in contact form.