13.Promise 콜백지옥을 무찌르자

3 minute read

1. Promise 란 무엇일까?

Javascript에서 제공하는 비동기를 간편하게 처리할수 있도록 도와주는 object이다.

2. Promise의 두가지 포인트

첫번째, state(상태)

  • Process가 무거운 operation(처리)를 하고 있는중인지, 기능 수행을 성공했는지 실패했는지 state(상태)에 대해서 이해하는것이 중요하다.

    • operation이 수행중일때는 : pending 상태

    • operation이 성공적으로 마칠때는 : fullfilled 상태

    • operation에서 문제가 발생할때는(파일을 찾을수 없거나 , 네트워크에서 문제가 발생) : rejected 상태

두번째, producer 와 consumer의 차이점

  • producer : 우리가 원하는 데이터를 제공하는 사람

  • consumer : 제공된 데이터를 사용하는 사람

3. Promise 만들기

Producer

  • Promise 는 resolve아 reject라는 콜백함수를 받는 executer(실행자)라는 콜백함수를 전달해줘야한다.
const promise = new Promise((resolve, reject) => {
  //doing some heavy work(network, read files 는 비동기적으로 처리하는것이 좋다. 왜?? 오래걸리기 때문에 동기적으로 하면 다른일을 하지 못함)

  console.log("doing something");
  setTimeout(() => {
    resolve("ellie"); //성공적으로 network or readfiles를 햇다면 resolve()함수를 사용한다.

    reject(new Error("no network"));
    //만약 성공적으로 받아오지 못했다면 밑에reject()함수가 실행되어 그 이유를 나타내준다.
  }, 2000);
});

꿀팁

  • promise가 만들어지게 되면 , 자동적으로 실행해버린다. 따라서 버튼을 눌러서 어떠한 network나 readfiles를 하기위해서는 이렇게 작성해서는 안된다.

Consumers : then, catch, finally

promise
  .then((value) => {
    console.log(value); //ellie
  })
  .catch((error) => {
    console.log(error); // no network
  }) //error를 잡기위함
  .finally(() => {
    console.log("final");
  });
  • 성공했을때 결과값 : doingSomething , ellie , final

  • 실패했을때 결과값 : doingSomething , no network , final

3. Promise chaining(연결하기)

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));
  • 이러게 Promise를 한번더 비동기화하여 전달할수 있다.

4. Error chaining(연결하기)

const getHen = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(""), 1000);
  });
};

const getEgg = (hen) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(`${hen}=>달걀`), 1000);
  });
};
const cook = (egg) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(`${egg}=>병아리`), 1000);
  });
};

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

// same code
// getHen()
//   .then(getEgg)
//   .then(cook)
//   .then(console.log);
  • 결과값 : 닭=>달걀=>병아리

4. Error chaining (2) , 에러가 발생했을때

const getHen = () => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(""), 1000);
  });
};

const getEgg = (hen) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => reject(new Error(`error! ${hen}=>"달걀"`)), 1000);
  });
};
const cook = (egg) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(`${egg}=>병아리`), 1000);
  });
};

getHen()
  .then((hen) => getEgg(hen))
  .catch((error) => {
    return "";
  })
  .then((egg) => cook(egg))
  .then(console.log)
  .catch(console.log);
  • getEgg()에서 발생한 에러를 다른것인 “빵”으로 대처하기 위해
.then((hen) => getEgg(hen))
  .catch((error) => {
    return "";
  })

을 쓴거다.

5. Callback Hell Example을 해결하는 방법

  • 기존
class UserStorage {
  loginUser(id, password, onSuccess, onError) {
    setTimeout(() => {
      if (
        (id === "ellie" && password == "dream") ||
        (id === "coder" && password === "academy")
      ) {
        onSuccess(id);
      } else {
        onError(new Error("not found"));
      }
    }, 2000);
  }

  getRoles(user, onSuccess, onError) {
    setTimeout(() => {
      if (user === "ellie") {
        onSuccess({ name: "ellie", 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.getRolesuser(
      user,
      (userWithRole) => {
        alert(
          `Hello" ${userWithRole.name}, you have a ${userWithRole.role} role`
        );
      },
      (error) => {
        console.log(error);
      }
    );
  },
  (error) => {
    console.log(error);
  }
);
  • 바뀐 후
class UserStorage {
  loginUser(id, password) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (
          (id === "ellie" && password == "dream") ||
          (id === "coder" && password === "academy")
        ) {
          resolve(id);
        } else {
          reject(new Error("not found"));
        }
      }, 2000);
    });
  }

  getRoles(user, onSuccess, onError) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        if (user === "ellie") {
          resolve({ name: "ellie", 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((user) => alert(`Hello" ${user.name}, you have a ${user.role} role`))
  .catch(console.log);

Leave a comment