JavaScript & Node.js

#.13 비동기 [Promise]

Haksae 2022. 1. 9. 15:44

* Promise

  • promise : JS에서 제공하는 비동기를 간편하게 처리할 수 있는 object
  • 비동기적인 것을 수행할 때 콜백함수 대신에 유용하게 쓸 수 있는 오브젝트
  • 정해진 장시간의 기능을 수행하고나서 정상적으로 기능이 수행되어졌다면 성공의 메시지와 함꼐 처리된 결과 값을 전달, 기능을 수행하다가 문제가 발생했다면 에러를 전달해줌

* promise 중요포인트 2가지

 1. State

  • 기능 수행이 성공했는지 실패했는지 이런 상태에 대한 이해 중요

 2. Producing vs Consumer

  • producing : 우리가 원하는 데이터를 제공하는 사람
  • consumer : 데이터를 필요로 하는 사람

1. Producer

  • promise를 만드는 순간 executor라는 콜백 함수가 바로 실행됨
  • 유의 : 사용자가 요구하지 않은 불필요한 네트워크 통신이 발생할 수 있음
  • resolve() : 기능을 성공적으로 수행되었을 때 호출
'use strict';

// Promise is a JavaScript object for asynchronous operation.
// State: pending -> fulfilled or rejected 
// Producer vs Consumer

// 1.Producer
// when new Promise is crated, the executor runs automatically
const promise = new Promise((resolve, reject)=>{ 
    // doing some heavy work (network, read files)
    console.log('doing something...');
		setTimeout(()=>{
        resolve('haksae'); // 콜백함수를 통해 전달
    }, 2000);
});
  • 예시 : 서버에서 어떤 일을 하다가 잘 마무리하고, resolve라는 함수를 통해 값 전달

2. Consumers : then, catch, finally

  1. then()
  • Promise가 정상적으로 수행이 되어서 resolve콜백 함수를 통해 전달한 값이 then(value)의 파라미터로 전달이 되어져서 들어옴
  • then은 promise도 전달이 가능하다.
promise.then((value) => {
	console.log(value);
});
  1. reject(), catch()
  • reject : 기능 수행에 에러가 발생되었을 때 호출
  • 에러 오브젝트에는 에러 이유를 잘 명시해야함
  • catch()
    • promise가 기능 수행에 에러가 발생하여 reject 콜백 함수를 통해 전달한 값이 catch(eooro)의 파라미터로 전달되어서 들어옴
const promise = new Promise((resolve, reject)=>{
    console.log('doing something...');
    setTimeout(()=>{
        // resolve('haksae');
        reject(new Error('no network'));
    }, 2000);
});

// Consumers: then, catch, finally
promise
    .then(value =>{
        console.log(value);
    })
    .catch(error =>{
        console.log(error);
    });
  1. finally()
  • 성공과 실패와 상관 없이 무조건 마지막에 호출되어지는 함수
.finally(()=>{
        console.log('finally');
    });

3. Promise chaining

  • then을 여러가지 비동기적인 함수도 같이 묶어서 처리할 수 있음

→ then은 값을 바로 전달할 수도 있고 Promise를 전달할 수도 있다.

const fetchNumber = new Promise((resolve, reject)=>{
    setTimeout(() => resolve(1), 1000);
});

// 비동기인 함수도 묶어서 처리
fetchNumber
    .then(num => num*2) // 2
    .then(num => num*3) // 6
    .then(num => {
        return new Promise((resolve, reject)=>{
            setTimeout(() => resolve(num-1), 1000); // 5
        });
    })
    .then(num => console.log(num));
const getHen = () =>
    new Promise((resolve, reject)=> {
        setTimeout(() => resolve('🐔'), 1000);
    });
const getEgg = hen => 
    new Promise((resolve, reject)=> {
        setTimeout(() => resolve(`${hen} => 🥚`), 1000);
    });
const cook = egg =>
    new Promise((resolve, reject) => {
        setTimeout(() => resolve(`${egg} => 🍳`), 1000);
    });

/*
getHen()
    .then(hen => getEgg(hen))
    .then(egg => cook(egg))
    .then(meal => console.log(meal));
*/

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

4. Error Handling

  • 만약 위의 프로미스에서 실패시 아래와 같은 에러가 발생한다.

  • 에러를 핸들링 하기 위해서 catch() 를 써야한다.
getHen()
     .then(getEgg)
     .then(cook)
     .then(console.log)
     .catch(console.log);

 

  • 에러가 발생하여도 중단되지 않고 대체방안으로 작동시키는 방법
getHen()
     .then(getEgg)
     .catch(error =>{
        return '🥐';  // getEgg에서 에러가 발생하여도 promise chain이 중단되지 않게 함
    })
     .then(cook)
     .then(console.log)
     .catch(console.log);

5. Callback - to - Promise (콜백지옥 해결)

// Callback Hell example
class UserStorage {
  loginUser(id, password) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (
          (id === "hak" && password == "sae") ||
          (id === "coder" && password == "academy")
        ) {
          resolve(id);
        } else {
          reject(new Error("not found"));
        }
      }, 2000);
    });
  }
  getRoles(user) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (user === "hak") {
          resolve({ name: "hak", role: "admin" });
        } else {
          reject(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 => alert(`Hello ${user.name}, you have a ${user.role} role`))
    .catch(console.log);

출처 : 드림코딩엘리 https://www.youtube.com/channel/UC_4u-bXaba7yrRz_6x6kb_w