- JavaScript is synchronous.
* synchronous(동기의, 동시 발생[존재]하는) <-> asynchronous(비동기의, 동시에 존재[발생]하지 않는) 
- Execute the code block in order after hoisting.
(hoisting된 이후부터 코드들이 위에서 아래로 순차적으로 자동 실행됨)
* hoisting(끌어 올리기, 들어올려 나르기): 변수 또는 함수 선언들이 자동적으로 코드 단의 제일 위로 올라가는 것. 
console.log('1'); 
console.log('2'); 
console.log('3'); 
console.log('1');
setTimeout(() => console.log('2'), 1000); 
console.log('3');
function printImmediately(print) {
	print();
}
printImmediately(() => console.log('hello'))
function printWithDelay(print, timeout) {
	setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
class UserStorage {
	loginUser(id, password, onSuccess, onError) {
		setTimeout(() => {
			if (
				(id === 'jiyaho' && password === '111') ||
				(id === 'yaho' && password === '222')
			) {
				onSuccess(id); 
			} else {
				onError(new Error('not found!')); 
			}
		}, 2000);
	}
	getRoles(user, onSuccess, onError) {
		setTimeout(() => {
			if (user === 'jiyaho') {
				onSuccess({ name: 'jiyaho', 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);
	}
);