Asynchronous processing of JS - (b) : promise - 2

zzwwoonn·2022년 5월 13일
0

Java Script

목록 보기
23/29

Promise Chaining

예제 1

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));
  1. 1초 있다가 숫자 1을 전달해주는 promise 생성
  2. fetchNumber가 성공적으로 잘 되면 그 숫자를 곱하기 2 해서 전달 (2를 전달)
  3. 위의 과정이 잘 됐을 경우에 곱하기 3 해서 전달 (6을 전달)
  4. 다른 서버에 보내서 다른 숫자로 변환된 값(숫자에 1을 뺀 값)을 받아온다
    이때 새로운 Promise(새로운 비동기)를 전달 (새로운 promise : 6에서 -1 하고 5를 전달)
  5. 그 받아온 숫자(5) 를 최종적으로 출력

then은 값을 바로 전달할 수도 있고(1,2,3), promise 객체 그 자체를 전달(4)할 수도 있다.

최종적으로 걸리는 시간은? 총 2초

Error 처리

const getHen = () => 
    new Promise((resolve, reject) => {
        setTimeout(() => resolve('🐓'), 1000);
    });
    // 닭을 받아오는 promise

const getEgg = hen => 
    new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${hen} => 🥚`), 1000);
    });
    // 받아온 닭으로부터 달걀을 받아오는 promise

const cook = egg => 
    new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${egg} => 🍳`), 1000);
    });    
    // 받아온 달걀로부터 요리를 만드는 promise

getHen() 					  	 	 // 1번
    .then(hen => getEgg(hen))    	 // 2번
    .then(egg => cook(egg))		 	 // 3번
    .then(meal => console.log(meal)) // 4번

1번 - 닭을 받아온다
2번 - 닭이 받아와지면 전달받은 닭(hen)을 이용해 getEgg 호출
3번 - 그것이 수행이 되면 받아온 달걀(egg)을 가지고 cook 호출
4번 - 요리가 완료(meal)된 다음에는 그걸 출력

총 3초가 걸리겠지

코드를 조금 깔끔하게 할 수 있다.
콜백 함수를 전달할 때 받아온 값을 바로 다음에 하나로 호출하는 경우 이를 생략 가능하다.

getHen()
    .then(getEgg)
    .then(cook)
    .then(console.log)

< 실행 결과 >

그럼 각각의 과정 도중에 Error 가 났다면 어떻게 각각을 처리해줄 것인가?

예를 들어 getEgg 에서 네트워크에 문제가 생겨 reject를 반환했다고 가정

const getEgg = hen => 
    new Promise((resolve, reject) => {
        setTimeout(() => reject(new Error(`error !!! ${hen} => 🥚`)), 1000);
    });
    // 받아온 닭으로부터 달걀을 받아오는 promise

이런 경우 각각의 구문 바로 밑에 catch로 에러를 핸들링 해주면 된다.
=> 다른 재료로 대체한다고 가정

도중 어떤 과정에 문제가 생겨도 전체적인 promise chain에 영향이 있으면 안된다.

getHen()
    .then(getEgg)
	.catch(error => {
  		return '🥖';
  	    // getEgg에서 문제가 발생할 경우 빵을 리턴
  		// 아래의 과정은 그대로 진행
	})
    .then(cook)
    .then(console.log)

< 실행 결과 >

콜백 지옥 해결하기

Before

class UserStorage {
	loginUser(id, password, onSuccess, onError) {
		setTimeout( () => {
			if (
				(id === 'seo' && password === '4074') ||
				(id === 'jiwon' && password === '8927')
			) {
				onSuccess(id);
			} else {
				onError(new Error('not found'));
			}
		}, 2000);
	}
	
	getRoles(user, onSuccess, onError) {
		setTimeout( () => {
			if (user === 'seo') {
				onSuccess({ name : 'seo', 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 are ${userWithRole.role}`);
			},
			error => {
				console.log(error);
			}
		);
	},
	error => {
		console.log(error);
	}
);

After (using promise)

class UserStorage {
	loginUser(id, password) {
      return new Promise((resolve, reject) => {
      	setTimeout( () => {
			if (
				(id === 'seo' && password === '4074') ||
				(id === 'jiwon' && password === '8927')
			) {
				resolve(id);
			} else {
				reject(new Error('not found'));
			}
		}, 2000);
      };
	}
	
	getRoles(user) {
      return new Promise((resolve, reject) => {
      	setTimeout( () => {
			if (user === 'seo') {
				onSuccess({ name : 'seo', 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)
  .then(userStorage.getRoles)
  // => .then(user => userStorage.getRoles(user))
  // 인자가 똑같으니 생략 가능
  .then(user => alert(`Hello, ${user.name}, you are ${user.role}`))
  .catch(console.log);

0개의 댓글

관련 채용 정보