자바스크립트는 기본적으로 동기(synchronous)로 동작한다.
동기(synchronous) : 웹이 호이스팅된 이후로 코드 블럭이 순차적으로(by order) 실행
호이스팅(hoisting) : var, function declaration - 변수 선언, 함수 선언 등이 자동으로 젤 위로 끌어올려지는 현상
콜백 함수에는 동기 콜백, 비동기 콜백이 있다.
console.log('1');
// 동기(synchronous)
setTimeout(() => console.log('2'), 1000);
// 비동기(asynchronous)
console.log('3');
// 동기(synchronous)
// 동기 콜백 함수(synchronous callback)
function printImmediately(print) {
print();
// 인자로 넘겨받은 함수
}
printImmediately(() => console.log('hello');
// 비동기 콜백 함수(asynchronous callback)
function printWidthDelay(print, timeout) {
setTimeout(print ,timeout);
// 인자로 넘겨받은 함수
}
printWidthDelay(() => console.log('async callback'), 2000);
위의 코드를 실행하면 !?
<실행 결과>
1
3
hello
(1초 있다가)
2
(1초 더 있다가, 총 2초)
async callback
함수 선언(printImmediately, printWidthDelay)은 호이스팅 되어 코드 젤 위로 옮겨지고 이벤트 큐에 넣어진다. 이후 코드가 순차적으로 실행되고 젤 마지막에 비동기 함수가 실행된다.
콜백 함수를 이용할 때 주의할 점 ⇒ 콜백 지옥
콜백 지옥 : 콜백 함수들을 계속 엮어가면서(nesting) 콜백 함수 안에 콜백 함수 콜백 함수 안에 콜백 함수~~~ 하는 방식으로 깊이(depth)가 계속 깊어지는 방식
ES6 Grammar Essentials (c) - Asynchronous
class UserStorage {
// 두가지의 API가 있다고 가정
loginUser(id, password, onSuccess, onError) {
// 기본적으로 id 와 ps를 받아오고
// 로그인이 정상적으로 됐다면 사용자 데이터와 함께 onSuccess 콜백 함수를 호출,
// 로그인에 실패 했다면(존재하지 않는 사용자거나, ps가 틀렸다거나, 네트워크에 문제가 있다거나
// => 에러 발생시 : onError 콜백 함수 호출
// 어느 정도의 시간 딜레이를 주면서 서버와 네트워크 한다고 가정
setTimeout( () => {
if (
(id === 'seo' && password === '4074') ||
(id === 'jiwon' && password === '8927')
) {
onSuccess(id);
} else {
onError(new Error('not found'));
}
}, 2000);
}
getRoles(user, onSuccess, onError) {
// 사용자의 정보를 받아서 사용자마다 가진 (admin, guest ~) 역할을 다시 서버로부터 요청
// loginUser 에서 한번에 받아오면 되지만 이렇게 따로 요청을 해야 하는 상황을 가정.
setTimeout( () => {
if (user === 'seo') {
onSuccess({ name : 'seo', role : 'admin' });
} else {
onError(new Error('no access'));
}
}, 1000);
}
}
내가 하고 싶은 일 (구현, 로직) - Task
const userStorage = new UserStorage();
const id = prompt('enter your id');
const password = prompt('enter your password');
// Task 1, 입력 받아오기
userStorage.loginUser(
// Task 2, loginUser 함수를 통해 로그인 프로세스 진행
id, // 인자1 , 아이디
password, // 인자2, 비밀번호
user => { // 인자3, 성공했을 때 실행할 콜백함수 (id 여야 하는데 흐름상 user라고 해둠)
userStorage.getRoles(
// Task 3, 로그인이 성공적으로 됐을 경우에만 그 정보를 이용해서 사용자의 역할을 요청
user, // 인자1, 사용자의 정보
userWithRole => { // 인자2, 성공시 실행할 함수 => 이 코드 블럭이 실행 되려면?
// Task 2의 과정(로그인)이 잘 되고,
// Task 3의 사용자 역할 요청이 잘 돼서, 정보를 받아온 경우
alert(`Hello, ${userWithRole.name}, you are ${userWithRole.role}`);
// Task 4, 받아온 사용자의 정보(이름, 역할) 화면에 출력
},
error => { // 인자3, 실패시 실행할 함수
console.log(error);
}
);
},
error => { // 인자4, 실패했을 때 실행할 콜백함수
console.log(error);
}
); // End Of userStorage.loginUser