JavaScript is synchronous. (동기)
Execute the code block by orger after hoisting.
hoisting: var, function declaration
console.log('1');
setTimeout(() => console.log('2'), 1000);
console.log('3');
// 1
// 3
// 2
function printImmediately(print) {
print();
}
printImmediately(() => console.log('hello'));
// 1
// 3
// hello
// 2
// * 모든 함수의 선언은 호이스팅이 되어 최상단으로 끌어올려진다.
// synchronous callback (동기)
function printImmediately(print) {
print();
}
// asynchronout callback (비동기)
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
console.log('1'); // 동기
setTimeout(() => console.log('2'), 1000); // 비동기
console.log('3'); // 동기
printImmediately(() => console.log('hello')); // 동기
printWithDelay(() => console.log('async callback!'), 2000); // 비동기
// 1
// 3
// hello
// 2 (1초 후 출력)
// async callback (2초 후 출력)
class UserStorage {
loginUser(id, password, onSuccess, onError) {
setTimeout(() => {
if (
(id === 'amanda' && password === 'dream') ||
(id === 'coder' && password === 'academy')
) {
onSuccess(id);
} else {
onError(new Error('not found');
}
}, 2000);
}
getRoles(user, onSuccess, onError) {
setTimeout(() => {
if (user === 'amanda') {
onSuccess({ name: 'amanda', role: 'admin' });
} else {
onError(new Error('no access');
}
}, 1000}
}
}
const userStorage = new UserStorage();
const id = propmt('enter your id');
const password = prompt('enter your password');
// LOGIN
userStorage.loginUser(
id,
password,
user => {
userStorage,getRoles(
user,
userWithRole => {
alert(`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`);
},
error => {}
);
},
error => { console.log(error) }
);
콜백 체인의 문제점
- 가독성이 떨어진다.
어디서 어떤식으로 연결되어 있는지 한눈에 가늠하기도 어렵고
비즈니스 로직을 한눈에 이해하기도 어렵다.- 에러가 발생하거나 디버깅을 해야하는 경우에도 어려움
문제가 생길 때 체인이 길어지면 길어질수록 디버깅하고 문제를 분석하는 것도 어렵고 유지보수가 힘들다.
state: pending 👉🏻 fulfilled or rejected
Producer vs Consumer
// Promise를 만드는 순간 전달한 excutor라는 콜백함수가 바로 실행된다.
const promise = new Promise((resolve, reject) => {
// doing some heavy work (network, read files)
console.log('doing something...');
setTimeout(() => {
resolve('amanda');
//reject(new Error('no network'));
}, 2000);
});
promise
.then(value => {
console.log(value);
// resolve = amanda
// reject = Uncaught: (in promise) Error: no network
})
.catch(error => {
console.log(error);
})
.finally(() => {
console.log('finally');
});
// ** 성공하던 실패하던 상관없이 어떤 기능을 마지막으로 수행하고 싶을 때 finally 사용
const fetchNumber = new Promise((resolve, reject) => {
setTimeout(() => resolve(1), 1000);
});
fetchNumber
.then(num => num * 2)
.then(num => num * 3)
.then(num => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve(num - 1), 1000);
});
})
.then(num => console.log(num)); // 5
// ** then 에서는 값을 바로 전달해도 되고 또 다른 promise를 전달할 수 있다.
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);
class UserStorage {
loginUser(id, password) {
return new Promise((resolve, reject) => {
setTimeout(() => {
if (
(id === 'amanda' && 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 === 'amanda') {
resolve({ name: 'amanda', role: 'admin' });
} else {
reject(new Error('no access');
}
}, 1000}
})
}
}
const userStorage = new UserStorage();
const id = propmt('enter your id');
const password = prompt('enter your password');
// LOGIN
userStorage.loginUser(id, password)
.then(userStorage.getRoles)
.then(user => alert(`Hello ${userWithRole.name},you have a ${userWithRole.role} role`));
.catch(console.log);