봐도 봐도 헷갈리는 resolve, reject

Joel An·2019년 2월 23일
32
  • 이 글은 프로미스의 개념이나 사용법을 알려주지 않습니다.
  • 양질의 정보를 기대한다면 배신감을 느낄 가능성이 높습니다.
  • 굳이 설명하면 이렇게 생각해보면 이해하기 쉬워요정도가 되겠습니다.
  • 프로미스를 공부중인데 헷갈리기만 한다면 한번쯤 읽어보시는 걸 추천합니다!

미리 보는 결론

  1. 비동기 작업은 성공 혹은 실패한다.
  2. 비동기 작업은 요청하는 쪽과 처리하는 쪽이 구분되어있다.
  3. 프로미스의 resolve, reject는 비동기 작업의 처리과정에서 성공/실패를 구분하는 방법이다.

안 읽어도 되는 서론

자바스크립트 공부를 막 시작했을 무렵 어디를 가도 프로미스라는 단어가 따라왔다.

딱봐도 엄청 중요한 거 같으니까 공부를 해봐야지!

콜백헬이 어쩌고....pending..fulfilled...rejected.. 체이닝이 가능....

"아 그렇구나~" (모름)

"콜백이 별로라서 만든거라는데 이것도 그냥 콜백아니야?" (아님)

"근데 이걸 어떻게 쓰라는거야?" (진짜 모름)

당시 나의 머리속

  • 콜백은 나쁜거!
  • 프로미스는 좋은거!
  • pending, fulfilled, rejected? 3가지 상태? 이름겁나 헷갈리네
  • promise.then(result=>{}) 이렇게 쓰는거라고?
  • new Promise((resolve,reject)=>{})? 얘는 왜 모양이 달라?
  • setTimeout === 뇌정지
  • 코드 보면 이해는 되는데 (아님) 이걸 어떻게 써야되지?

공부를 하면 할수록 이해가 되기는 커녕 머리속은 뒤죽박죽이 되어갔다.

그렇다고 프로미스를 안 쓸 수도 없는 노릇이니

겉핥기 수준의 이해도를 가지고 프로젝트에서 프로미스를 사용하기 시작했고,

삽질에 삽질을 거듭한 끝에 어느정도 활용할 수는 있게되었다.

조금이나마 경험이 쌓였고, 프로미스 관련 글을 읽으면 바로 이해할 수 있게 됐으니 해피한 엔딩인가? 아니다.

할 줄 아는 것누군가에게 알려줄 수 있는 것은 다르다. 내가 알고 있(다고 착각하)는 내용을 정리할 겸,

뭘 모르는지 모르는 상태에서 도움이 될 만한. 모르는 사람의 입장에서 쓰여진 안내서를 쓰고싶은 생각이 들었다.

그래서 쓰게 된 글이고, 굉장히 두서가 없이 쓰인 글이라ㅎㅎ 읽다가 화가 나는 사람이 없기를 빈다.

안 읽어도 되는 서문까지 읽어주셔서 감사하다는 인사를 드리며 앞서 말한대로 두서없이 시작하도록 하겠다.


진짜 서론

프로미스에 대해서 막 공부를 시작했을 때, 이런 생각을 했었다.

  • promise.then(result=>{}) 이렇게 쓰는거라고?
  • new Promise((resolve,reject)=>{})? 얘는 왜 모양이 달라?

분명히 봤던 내용인데, 매번 볼 때마다 까먹고 헷갈렸다.

then()은 눈에 익었는데, resolve, reject는 예제 말고는 본 적이 없어서 그런지 봐도 봐도 처음보는 거 같았다.

지금 생각해보면 전혀 어려운 게 아니었는데 왜 그렇게 헷갈렸을까?

기본적인 내용을 잊고, 달을 가리키는데 손가락만 보았기 때문이다.

콜백 함수부터 제대로 이해하자.

내가 했던 실수는 콜백 함수를 알고있다고 착각한 것이다.

  1. 비동기 요청과 함께 콜백 함수를 전달한다.
  2. 비동기 요청이 처리된다.
  3. 전달한 콜백 함수가 실행된다.

너무도 당연한 말이지만, 당연한 것 만큼 잊기 쉬운 것도 없다.

콜백을 이용해 비동기 처리를 몇번 해보면, 비동기 처리를 "요청"하는 입장에서만 생각하게 된다.

내가 작성한 콜백함수를 누군가 실행한다는 사실은 자연스럽게 잊게 되고, 결국 프로미스의 생성사용이 헷갈리게 되는 원인이된다.

간단한 예제를 통해서 비동기 요청을 "처리"하는 입장을 고려해보자.


내가 만든 콜백 함수는 어떻게 실행될까?

주의 : 사용된 예제 코드는 실제로 동작하지 않습니다.

콜백함수를 이용해 비동기 작업을 요청하는 예시를 보자.

// App.js
import DB from './DB.js';

DB.getAllUsers( function myCallback(error, users) {
  if(error) {
    console.log('에러 발생!');
    console.log(error);
    return;
  }

  console.log('성공!');
  console.log(users);
})

DB에 모든 유저의 정보를 요청한 뒤, 그대로 출력하는 간단한 코드다.

  1. myCallback 이라는 함수를 작성해서 DB.getAllUsers()의 인자로 전달했다.
  2. 실패할 경우에 대비해서 myCallback 함수의 인자로 error도 받는다.

정도만 신경써보자.


DB는 어떻게 myCallback()을 처리할까?

// DB.js

const user_list = ['철수', '영희', '삼식이', '봉식이'];

function getAllUsers (callback_function) {
  if(user_list.length === 0) {
    callback_function(new Error('아무도 없다!'), undefined);
    return;
  }

  callback_function(undefined, user_list);
}

getAllUsers라는 함수는 callback_function이라는 인자를 받아서,

유저가 없으면 callback_function( 에러, undefined )

유저가 있으면 callback_function( undefined, 유저목록 ) 형태로 실행한다.


첫 번째에는 에러를, 두 번째에는 유저목록을 넣어서 실행하는 것은 하나의 약속이다.

이 약속만 지킨다면 누구든지

function myCallback(error, users) {
  // 하고 싶은 일
}

위와 같은 형태로 콜백함수를 작성하여 DB.js에 비동기 작업을 요청할 수 있다.


작은 결론

  1. 비동기 요청은 성공 혹은 실패한다.
  2. 비동기 작업을 요청하는 사람은 성공하는 경우/실패하는 경우를 고려해야 한다.
  3. ★ 비동기 작업을 처리하는 사람도 성공하는 경우/실패하는 경우를 고려해야 한다.

3번의 상황을 고려해야, Promise 객체의 resolve, reject를 헷갈리지 않고 이해할 수 있다.

// 아무 생각없이 아래 코드를 보면 헷갈리기만 한다.

new Promise((resolve, reject)=>{
  if(조건) {
    resolve('성공!');
  }
  reject('실패');
})

DB.js를 콜백 방식에서 프로미스 방식으로 바꾸는 예제를 보면서 확인해보자.

// DB.js

const user_list = ['철수', '영희', '삼식이', '봉식이'];

// 콜백 방식
function getAllUsers (callback_function) {
  if(user_list.length === 0) {
    callback_function(new Error('아무도 없다!'), undefined);
    return;
  }

  callback_function(undefined, user_list);
}

// 프로미스 방식
function getAllUsers () {
  return new Promise((resolve, reject)=>{
    if(user_list.length === 0) {
      // 실패
      reject(new Error('아무도 없다!'))
    } else {
      // 성공
      resolve(user_list)
    }
  })
}

코드를 이해못해도 괜찮다.

콜백 방식이 성공/실패를 구분하는 방법은 콜백함수의 인자 위치(순서)이고

프로미스 방식은 성공/실패resolve/reject 호출로 구분된다는 것만 확인하면 된다.

결론

  1. 비동기 작업은 성공 혹은 실패한다.
  2. 비동기 작업은 요청하는 쪽과 처리하는 쪽이 구분되어있다.
  3. 프로미스의 resolve, reject는 비동기 작업의 처리과정에서 성공/실패를 구분하는 방법이다.

뜬구름잡는 얘기처럼 들릴 수도 있겠다.

하지만 프로미스는 비동기 작업과 연관이 깊고, 비동기 작업은 요청하는 쪽처리하는 쪽이 나뉘어져 있기 때문에 반드시 구분해서 생각을 해야 정확하게 이해할 수 있다.

어려운 내용일수록 기본에 충실해야 편안하게 이해할 수 있다. 봐도봐도 모르겠다면 내가 놓치고 있는 기본적인 부분이 없는지 차분하게 생각해보자!

profile
I DON'T KNOW JS ㅜㅜ

5개의 댓글

comment-user-thumbnail
2019년 2월 24일

Promise 가, 옛날에 처음 봤을땐 이게 뭐지 싶었는데
코드를 직접 몇번 작성해봐야 이해되더라구요!

답글 달기
comment-user-thumbnail
2020년 8월 27일

아,,,이제야,,,이런 좋은 글을 보다니 ㅠ ㅠ항상 의미없이 쓰던코드가 이제야 눈에 확들어옵니다, 너무 설명 잘해주셔서 금방이해갔습니다 ㅠ ㅠ 감사합니다

답글 달기
comment-user-thumbnail
2021년 8월 3일

진짜 모르는 사람입장에서 적어준느낌 잘보고 가요~ ㅋㅋ

답글 달기
comment-user-thumbnail
2022년 9월 14일

ㅋㅋㅋㅋㅋㅋㅋ당시 머리속 공감되네요 ㅠ

답글 달기
comment-user-thumbnail
2024년 2월 20일

new Promise((resolve, reject) => {
pool.getConnection()
.then(conn => {

글 잘 읽어보았습니다. 저도 생각해보니 콜백에 대해서 명확히 이해하지 못한 상태였던거 같습니다.
아직도 그렇거 같구요 ㅎㅎ 질문 하나 드려도 될까요?
위 코드에서 (resolve, reject) 부분은 익명 콜백 함수인거죠..?
마찬가지로 아래에 getConnection 을 성공했을때 (then) 뒤에 인자로 오는 conn 도 콜백함수의 인자인거구요. 저런 형태들이 모두 콜백함수로 이해했는데 맞는지 모르겠네요. 다만 resolve 든 conn 이든 인자의 값들은 각각 정해진 다른 형태로 되어있구요.

답글 달기