3-8. Promise(콜백 지옥에서 우리를 구원하다)

2022. 6. 21. 23:53React/한입 크기로 잘라 먹는 리액트(React.js)

콜백지옥

비동기 작업이 가질 수 있는 3가지 상태

resolve상태, reject상태 기억!!

function isPositive(number, resolve, reject) {
  setTimeout(() => {
    if (typeof number === "number") {
      // 성공 -> resolve
      resolve(number >= 0 ? "양수" : "음수");
    } else {
      // 실패 -> reject
      reject("주어진 값이 숫자형 값이 아닙니다.");
    }
  }, 2000);
}

isPositive(
  2,
  (res) => {
    console.log("성공적으로 수행 됨 : ", res);
  },
  (err) => {
    console.log("실패 하였음 : ", err);
  }
);

이렇게 callback함수를 통해 비동기처리로 성공 및 실패를 내보았다.

 

Promise를 통해서 비동기 처리를 해보자

function isPositive(number, resolve, reject) {
  setTimeout(() => {
    if (typeof number === "number") {
      // 성공 -> resolve
      resolve(number >= 0 ? "양수" : "음수");
    } else {
      // 실패 -> reject
      reject("주어진 값이 숫자형 값이 아닙니다.");
    }
  }, 2000);
}

function isPositiveP(number) {
  const executor = (resolve, reject) => {
    // 실행자
    setTimeout(() => {
      if (typeof number === "number") {
        // 성공 -> resolve
        console.log(number);
        resolve(number >= 0 ? "양수" : "음수");
      } else {
        // 실패 -> reject
        reject("주어진 값이 숫자형 값이 아닙니다.");
      }
    }, 2000);
  };
  const asyncTask = new Promise(executor);
  return asyncTask;
}
isPositiveP(101);

// isPositive(
//   2,
//   (res) => {
//     console.log("성공적으로 수행 됨 : ", res);
//   },
//   (err) => {
//     console.log("실패 하였음 : ", err);
//   }
// );

 

여기서 isPositiveP의 반환 함수는 Promise인것을 확인할 수 있다.

여기서 isPositiveP의 반환 함수는 Promise인것을 확인할 수 있다.

Promise를 반환한다는 것은, 이 함수가 비동기 작업을 하고 작업의 결과를 Promise 객체로 반환받아서 사용할수 있는 함수

 

Promise의 비동기 처리의 결과값을 사용하는 방법

function isPositive(number, resolve, reject) {
  setTimeout(() => {
    if (typeof number === "number") {
      // 성공 -> resolve
      resolve(number >= 0 ? "양수" : "음수");
    } else {
      // 실패 -> reject
      reject("주어진 값이 숫자형 값이 아닙니다.");
    }
  }, 2000);
}

function isPositiveP(number) {
  // executor는 실행자로, 비동기 함수를 실행하는 것
  const executor = (resolve, reject) => {
    setTimeout(() => {
      if (typeof number === "number") {
        // 성공 -> resolve
        console.log(number);
        resolve(number >= 0 ? "양수" : "음수");
      } else {
        // 실패 -> reject
        reject("주어진 값이 숫자형 값이 아닙니다.");
      }
    }, 2000);
  };
  // 실행시키는 방법
  // new로 promise 객체를 생성함으로 exector를 넘겨주면 바로 수행 됨
  const asyncTask = new Promise(executor);
  // 그래서 반환 값이 Promise가 된다.
  // Promise 반환 함수 - 비동기 작업을 하고, 작업의 결과를 Promise 객체로 받아서 이용할 수 있음
  return asyncTask;
}
const res = isPositiveP(101);

res
  .then((res) => {
    console.log("작업 성공 : ", res);
  })
  .catch((err) => {
    console.log("작업 실패 : ", err);
  });

// isPositive(
//   2,
//   (res) => {
//     console.log("성공적으로 수행 됨 : ", res);
//   },
//   (err) => {
//     console.log("실패 하였음 : ", err);
//   }
// );

 

Promise를 통해 Callback 지옥을 벗어나보자.

아래는 콜백 지옥 함수

function taskA(a, b, cb) {
  setTimeout(() => {
    const res = a + b;
    cb(res);
  }, 3000);
}

function taskB(a, cb) {
  setTimeout(() => {
    const res = a * 2;
    cb(res);
  }, 3000);
}

function taskC(a, cb) {
  setTimeout(() => {
    const res = a * -1;
    cb(res);
  }, 3000);
}

taskA(3, 4, (a_res) => {
  console.log("task A : ", a_res);
  taskB(a_res, (b_res) => {
    console.log("task B : ", b_res);
    taskC(b_res, (c_res) => {
      console.log("task C : ", c_res);
    });
  });
});

아래와 같이 이렇게 만들었는데 또 콜백 헬이 나타났다.

function taskA(a, b) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a + b;
      resolve(res);
    }, 3000);
  });
}

function taskB(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * 2;
      resolve(res);
    }, 3000);
  });
}

function taskC(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * -1;
      resolve(res);
    }, 3000);
  });
}

taskA(5, 1).then((a_res) => {
  console.log("A RESULT : ", a_res);
  taskB(a_res).then((b_res) => {
    console.log("B RESULT : ", b_res);
    taskC(b_res).then((c_res) => {
      console.log("C RESULT : ", c_res);
    });
  });
});

--> then을 이렇게 사용하는것이 아니어서 그렇다.

그래서 아래와 같이 넣을 수 있는데

function taskA(a, b) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a + b;
      resolve(res);
    }, 3000);
  });
}

function taskB(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * 2;
      resolve(res);
    }, 3000);
  });
}

function taskC(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * -1;
      resolve(res);
    }, 3000);
  });
}

// then chaining
taskA(5, 1)
  .then((a_res) => {
    console.log("A RESULT : ", a_res);
    return taskB(a_res);
  })
  .then((b_res) => {
    console.log("B RESULT : ", b_res);
    return taskC(b_res);
  })
  .then((c_res) => {
    console.log("C RESULT : ", c_res);
  });

  // callback hell
  // taskA(5, 1).then((a_res) => {
  //   console.log("A RESULT : ", a_res);
  //   taskB(a_res).then((b_res) => {
  //     console.log("B RESULT : ", b_res);
  //     taskC(b_res).then((c_res) => {
  //       console.log("C RESULT : ", c_res);
  //     });
  //   });
  // });

then method들을 이어서 사용할 수 있다.

이를 then chaining이라고 한다.

then chaining은 중간에 뚝 끊을 수 있는데, callback hell인 구문은 계속 이어져서 해야하기 때문에 then chaining이 좋음

function taskA(a, b) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a + b;
      resolve(res);
    }, 3000);
  });
}

function taskB(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * 2;
      resolve(res);
    }, 3000);
  });
}

function taskC(a) {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
      const res = a * -1;
      resolve(res);
    }, 3000);
  });
}

// then chaining
const bPromiseResult = taskA(5, 1).then((a_res) => {
  console.log("A RESULT : ", a_res);
  return taskB(a_res);
});

console.log("this is the blank");

bPromiseResult
  .then((b_res) => {
    console.log("B RESULT : ", b_res);
    return taskC(b_res);
  })
  .then((c_res) => {
    console.log("C RESULT : ", c_res);
  });

// callback hell
// taskA(5, 1).then((a_res) => {
//   console.log("A RESULT : ", a_res);
//   taskB(a_res).then((b_res) => {
//     console.log("B RESULT : ", b_res);
//     taskC(b_res).then((c_res) => {
//       console.log("C RESULT : ", c_res);
//     });
//   });
// });

so, 가독성 있고 깔끔한 비동기 처리를 할 수 있게 된다.