배달시 그릇 상태: 짜장면 담김
식사 후 그릇 상태: 비워짐
이동시 그릇 상태: 비워짐
: 특정 로직의 실행이 끝날 때까지 기다려주지 않고 나머지 코드 먼저 실행
배달시 그릇 상태: 짜장면 담김
이동시 그릇 상태: 짜장면 담김
식사 후 그릇 상태: 비워짐
동기식이라면 배달원은 손님이 식사 마칠 때까지 기다린 후 다음 장소로 배달
화면에서 데이터를 서버로 요청했을 때 응답을 마냥 기다릴수만은 없다...
동기는 동일한 기찻길 위의 기차들
비동기는 다른 선로에 기차 배치
비동기로 주어진 일을 마친 후 실행되는 함수: 콜백 함수
여기선 setTimeout() 안의 anonymous 함수인 function ()이 콜백함수!
setTimeout()은 Web API의 한 종류! seconds * 1000만큼 기다렸다가 로직 실행한닷!! (1000 === 1초)
But 자바 스크립트는 단일 쓰레드로 돌아가는 synchronous한 언어인데 비동기 프로그래밍이 어떻게 가능할까?
JS 뿐만아니라 Web API라는 것도 같이 동작한다
Web API는 타이머, 파일에서 데이터를 읽어오기 등의 시간 관련 작업을 담당
JS의 단일 쓰레드에서 비동기로 처리된 함수를 읽으면 Web API로 비동기 코드가 처리된 후 테스크 큐로 들어가 다시 JS의 단일 쓰레드로 들어간다
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
function printImmedeately(print){
print();
} // declaration은 위로 가겠져?
printImmedeately(() => console.log('sync'));
function printWithDelay(print, timeout){
setTimeout(print, timeout);
} // declaration은 위로 가겠져?
printWithDelay(() => console.log('async'), 2000);
class UserStorage{
loginUser(id, password, onSuccess, onError){
setTimeout(() => {
if(
(id === 'comet' && password === 'sweet') ||
(id === 'glen' && password === 'morange')
){
onSuccess(id);
} else{
onError(new Error('not found'));
}
}, 2000);
}
getRoles(user, onSuccess, onError){
setTimeout(() =>{
if (user === 'comet'){
onSuccess({name: 'comet', role: 'admin'});
} else{
onError(new Error('no access'));
}
})
}
}
const userStorage = new UserStorage();
const id = prompt('Enter your id');
const password = prompt('Enter you 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);
}
)
고3때 수학선생님 찾는 프로그램
콜백함수의 연속... 콜백지옥...가독성 떨어지고 디버깅은 죽음이다...
const promise = new Promise((resolve, reject) => {
// doing some heavy work (network, read files)
console.log('doing something');
setTimeout(() => {
//resolve('comet');
reject('no network');
}, 2000);
});
promise
.then(value => { // resolve는 then에서 걸린다 - resolve의 값 받아옴
console.log(value);
})
.catch(error => { // error는 catch에서 걸린다 - reject의 값 받아옴
console.log(error);
})
.finally(() => { // finally는 성공/실패 상관없이 무조건 실행되는 구문
console.log('finally');
});
// 3. Promise chaining
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num*2) // then으로 resolve의 값을 연쇄적으로 불러오게 됨
.then(num => num*3)
.then(num => { // then의 param으로 new Promise도 들어올 수 있다
return new Promise((resolve, reject) =>{
setTimeout(() => resolve(num - 1), 1000);
});
})
.then(num => console.log(num));
catch 문을 에러날 곳 직전에 써야 에러처리를 잘할 수 있음
// 4. Error Handling
const getHen = () => // 이거 에로우함수 왜 {}로 감싸면 안됨??
new Promise((resolve, reject) => {
setTimeout(() => resolve('Chicken'), 1000);
});
const getEgg = hen =>
new Promise((resolve, reject) => {
setTimeout(() => reject(new Error(`Error! ${hen} -> egg`)), 1000);
});
const getFri = egg =>
new Promise((resolve, reject) => {
setTimeout(() => resolve(`${egg} -> fri`), 1000);
});
getHen()
.then(getEgg)
.catch(error => { // catch문을 에러날 곳 직전에 써야 핸들링이 잘 된다
return 'pork';
})
.then(getFri)
.then(console.log)
;
//.then(egg => getFri(egg)) - 한가지를 받아서 넣는 경우 이처럼 생략ㄱㄴ
앞선 콜백지옥을 promise문으로 고친 코드이다
'use strict';
// Callback Hell example
class UserStorage{
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if(
(id === 'comet' && password === 'sweet') ||
(id === 'glen' && password === 'morange')
){
resolve(id);
} else{
reject(new Error('not found'));
}
}, 2000);
});
};
getRoles(user) {
return new Promise((resolve, reject) => {
setTimeout(() =>{
if (user === 'comet'){
resolve({name: 'comet', role: 'admin'});
} else{
reject(new Error('no access'));
}
}, 1000);
});
};
}
const userStorage = new UserStorage();
const id = prompt('Enter your id');
const password = prompt('Enter you password');
userStorage.loginUser(id, password)
.then(userStorage.getRoles)
.then(user => alert(`Hello ${user.name}, you have a ${user.role} role`))
.catch(console.log);
// async를 붙이면 이 코드블럭이 자동으로 promise문으로 바뀌는 느낌이다
async function fetchUser() {
// do network request in 10 secs...(대충 오래걸리는 작업)
// 동기로 하면 여기서 10초이상을 머무르며 다른 동작이 실행이 안되겠지?
// + promise쓸 때 resolve, reject없이 그냥 return쓰면 promise에서 pending으로 머문다
return 'comet';
}
const user = fetchUser()
user.then(console.log);
console.log(user);
function delay(ms){
return new Promise(resolve => setTimeout(resolve, ms));
}
// await 없이 2초 딜레이를 주는 코드를 짜려면 이처럼 해야함
// function getApple{
// return delay(2000)
// .then(() => 'banana');
// }
async function getApple(){
await delay(2000);
//throw 'error';
return 'apple';
}
async function getBanana(){
await delay(1000);
return 'banana';
}
but apple과 banana를 동시에 호출하는건 어케 구현하지이?
function pickFruits() {
return getApple()
.then(apple => {
return getBanana()
.then(banana => `${apple} + ${banana}`);
})
}
pickFruits().then(console.log);
async function pickFruits() {
try{
const apple = await getApple();
const banana = await getBanana();
} catch{
console.log("error occured");
}
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
async function pickFruits() {
const applePromise = getApple();
const bananaPromise = getBanana();
const apple = await applePromise;
const banana = await bananaPromise;
return `${apple} + ${banana}`;
}
pickFruits().then(console.log);
function pickAllFruits() {
return Promise.all([getApple(), getBanana()])
.then(fruits => fruits.join(' + '));
}
pickAllFruits().then(console.log);
function pickOnlyOne() {
return Promise.race([getApple(), getBanana()])
}
pickOnlyOne().then(console.log);
class UserStorage{
loginUser(id, password){
return new Promise((resolve, reject) => {
setTimeout(() =>{
if(
(id === 'comet' && password === 'sweet') ||
(id === 'glen' && password === 'morange')
){
resolve(id);
} else{
reject(new Error('no access'));
}
}, 1000);
});
}
getRoles(user){
return new Promise((resolve, reject) => {
setTimeout(() => {
if (user === 'comet'){
resolve({name: 'comet', role: 'admin'});
} else{
reject(new Error('no access'));
}
}, 1000);
});
}
async getUserWithRole(user, password){
const id = await this.loginUser(user, password);
const role = await this.getRoles(id);
return role;
}
}
const userStorage = new UserStorage();
const id = prompt('Enter your id');
const password = prompt('Enter you password');
userStorage
.getUserWithRole(id, password)
.catch(console.log)
.then(console.log);
https://www.youtube.com/watch?v=m0icCqHY39U
https://joshua1988.github.io/web-development/javascript/javascript-asynchronous-operation/