1. 동기와 비동기
JavaScript is synchronous.
자바스크립트는 동기적이다.
Execute the code block in order after hoisting.
=> hoisting이 된 이후부터 우리가 작성한 코드의 순서에 맞춰서 하나하나 동기적으로 실행된다.
ex)
console.log('1');
console.log('2');
console.log('3');
코드를 위와 같이 작성하면, console에 1, 2, 3 순서대로 출력된다.
# asynchronous : 비동기
: 언제 코드가 실행될 지 예측할 수 없는 것.
예시) "setTimeout"이라고 하는 web API(브라우저에서 제공하는 API)
우리가 지정한 시간이 지나면 전달한 콜백함수를 호출한다.
setTimeout에는 Time handler라는 콜백함수 + 얼마의 시간을 줄건지 timeout
즉, setTimeout는 지정한 시간 이후, 전달한 콜백함수가 실행된다.
console.log('1');
setTimeout(function() {
console.log('2');
}, 1000); //millisecond. 1,000 = 1초
console.log('3');
이게 어떻게 된걸까?
=> 자바스크립트 엔진은 코드를 제일 위에서부터 밑으로 실행하게 된다.(동기적으로)
1) console.log("1"); → 1 출력
2) setTimeout -> 브라우저 API이므로 "브라우저야, 너에게 요청이 하나 왔어. 1초 후에 전달해준 콜백함수를 실행해줘"
브라우저 API는 무조건 브라우저에게 먼저 요청을 보내게 된다.
응답을 기다리지 않고 바로 console.log('3')으로 넘어가게 된다.
3) console.log("3"); → 3 출력
4) 브라우저에서 1초 후, 1초 지났으니 콜백함수 실행해!
5) console.log("2"); → 2 출력
이게 비동기적 실행방법.
2. 콜백 마지막 정리
지금 당장 실행하지 않고, 1초 후에 "내 함수를 나중에 call 해줘!"라고 해서 callback 함수.
그리고, 보통은 콜백함수를 함수선언식이 아닌, 화살표함수(arrow function)으로 표현한다.
그렇다면 callback은 항상 비동기일때만 쓰이나?
→ NO!
callback도 2가지의 경우로 나누어진다.
즉각적으로 실행하는 Synchronous callback
언제 실행될지 알 수 없는 Asynchronous callback
1) Synchronous callback
console.log('1');
setTimeout(function() {
console.log('2');
}, 1000); //millisecond. 1,000 = 1초
console.log('3');
function printImmediately() {
print(); //callback함수를 받아서 바로 실행
}
printImmediately(() => console.log('hello'));
위와 같은 코드가 있다면, 출력은 어떻게 될까?
1, 3, hello, 2
이 순서로 출력된다.
과연, 자바스크립트 엔진이 어떻게 했을까?
function printImmediately() { //호이스팅으로 함수선언문은 위로 올라감.
print(); //callback함수를 받아서 바로 실행
}
console.log('1'); // 1
setTimeout(function() {
console.log('2'); //4
}, 1000);
console.log('3'); // 2
printImmediately(() => console.log('hello')); //3
2) Asynchronous callback
console.log('1');
setTimeout(function() {
console.log('2');
}, 1000);
console.log('3');
// Synchronous callback
function printImmediately() {
print();
}
printImmediately(() => console.log('hello'));
// Asynchronous callback
function printWithDelay(print, timeout) {
setTimeout(print, timeout);
}
printWithDelay(() => console.log('async callback'), 2000);
과연, 자바스크립트 엔진이 어떻게 했을까?
function printImmediately() { //호이스팅
print();
}
function printWithDelay(print, timeout) { //호이스팅
setTimeout(print, timeout);
}
console.log('1'); // 1 - 동기
setTimeout(function() { // - 비동기. 옆에 빼놓자.
console.log('2');
}, 1000);// 4
console.log('3'); // 2 - 동기
printImmediately(() => console.log('hello')); // 3 - 동기
printWithDelay(() => console.log('async callback'), 2000); //5 - 비동기
콜백은 이렇게 유용하게 쓰일 때도 있지만, "콜백지옥"이라는 말도 있다.
3. 콜백 지옥 체험
// 사용자의 data를 backend에서 받아오기
class UserStorage { // 총 2가지의 API가 있다.
loginUser(id, password, onSuccess, onError) { //사용자가 login. id, password 받아오기
setTimeout(() => {
if((id === 'ellie' && password === 'dream') || (id === 'coder' && password === 'academy'))
{
onSuccess(id); //login성공 -> onSuccess콜백함수 호출
} else {
onError(new Error('not found')); //login실패 -> onError콜백함수 호출
}
)
}, 2000);
}
getRoles(user, onSuccess, onError) { //사용자의 data를 받아서 role을 서버에 요청.
setTimeout(() => {
if(user === 'ellie') {
onSuccess({name: 'ellie', role: 'admin'});
} else {
onError(new Error('no access'));
}
} ,1000);
}
}
const userStorage = new UserStorage(); //class를 이용하여 backend와 통신
const id = prompt("enter your id"); //사용자에게 id를 받아온다. 브라우저 API 중 하나인 prompt
const password = prompt("password"); //사용자에게 password를 받아온다.
userStorage.loginUser(
id,
password,
(user) => { // login 성공
userStorage.getRoles(
user,
(userWithRole) => {
alert(
`Hello ${userWithRole.name}, you have a ${userWithRole.role} role`
);
},
(error) => { // role얻어오기 실패(id가 'ellie'가 아닐 경우)
console.log(error);
}
);
},
(error) => { // login 실패
console.log(error);
}
);
1/ 사용자에게 id, password를 입력을 받아온다.
2/ 로그인
3/ 로그인을 성공하면 id를 받아온 후, role을 다시 요청한다.
4/ 역할을 요청해서 역할을 받아와주면 name, role을 출력하자.
UserStorage를 이용하여 backend와 통신을 해보자.
4. 콜백 체인의 문제점
콜백함수 안에서 다른 것을 호출하고, 그 안에서 또다른 콜백함수를 호출하고, 다른 것을 호출하고.. 하면 콜백 지옥!
1/ 읽기가 너무 힘들다. 가독성이 떨어진다.
2/ 그래서 디버깅하기 굉장히 힘들다.
3/ 유지보수도 어렵다.
=> promise를 이용하여 어떻게 깔끔하고 작성할 수 있는지 알아보자!
**참고영상 :
https://www.youtube.com/watch?v=s1vpVCrT8f4&list=PLv2d7VI9OotTVOL4QmPfvJWPJvkmv6h-2&index=11
'JavaScript' 카테고리의 다른 글
callback함수란? (0) | 2023.12.23 |
---|---|
원시 값과 객체의 비교 (1) | 2023.12.19 |
2차원 배열에서의 index error 처리 (0) | 2023.10.27 |
[JavaScript] 옵셔널 체이닝 (?.) (0) | 2023.10.27 |
[JavaScript] 논리적 AND 연산자 (&&) (0) | 2023.10.26 |