Asynchronous processing of JS - (a) : sync, async, callback

zzwwoonn·2022년 5월 13일
0

Java Script

목록 보기
21/29

JS 동기, 비동기, 콜백

자바스크립트는 기본적으로 동기(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

  1. 사용자의 아이디, 패스워드 입력 받아오기
  2. 이 정보를 이용해서 서버에 로그인
  3. 로그인이 성공적으로 된다면 그 아이디를 이용해서 서버에 그 사용자의 역할을 요청
  4. 요청이 성공적으로 됐다면 받아온 정보 (이름, 역할)을 화면에 출력
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

콜백 체인(콜백 지옥)의 문제점

  1. 읽기가 힘들다.
    (가독성이 떨어진다)
  2. 비지니스 로직을 한 눈에 보고 이해하기 힘들다.
    (로그인을 먼저 하고 성공했을 때에 다시 역할 정보 요청을 하는구나)
  3. 에러가 발생하거나 디버깅을 해야할 경우 문제의 분석이 굉장히 어렵다.
    (어디서 어떻게 에러가 났는지 확인이 어려움)
  4. 유지 보수가 어렵다.

콜백 지옥을 해결하기 위한 방법

  1. 코딩 패턴으로 해결 → 각각의 콜백 함수를 분리
  2. Promise
  3. Async

0개의 댓글

관련 채용 정보