1. Callback 콜백함수

아마 이 내용을 알기 전까지 우리는 자바스크립트에서 어느정도 함수도 다루고 반복문도 쓰고, 조건문도 쓰고, 알고리즘을 통해 클래스도 만들 수 있고, 여러가지를 처리할 수 있었다고 생각할 것이다.

하지만 실제로 우리가 사용하는 알고리즘은 '동기화' 방법을 사용해서 매우 멍청한데, 모든 함수를 순차대로 처리하기 때문이다. 이는 마치 한 사람이 여러 업무를 처리해야 하는 상황 가운데 놓인 것과 같다. 왜냐하면 한 사람이 동시에 여러가지 일을 처리할 수는 없기 때문이다.
하지만 일을 효율적으로 처리할 수 있도록 도와주는 것이 바로 '비동기화'이다. 간단한 아래 예시를 통해 알 수 있다.

멍청한 '동기화' & 똑똑한 '비동기화'


하지만 우리는 앞서 CallbackSetTimeout이라는 방법을 통해 함수를 인자로 넘겨받는 아주 우수한 방법을 배웠다. 이를 통해서 우리는 비동기화를 이뤄낼 수 있다. 아래와 같이 말이다.

const printString = (string) => {
  setTimeout(
    () => {
      console.log(stirng)
    },
    Math.floor(Math.random() * 100) + 1
  )}

const printAll = () => {
  printString('A')
  printString('A')
  printString('A')
}

printAll()

이처럼 우리는 setTimeout을 통해 쉽고 간단히 비동기화를 이뤘는데, 대신 순서를 지켜낼 수 없다. 어떻게 보면 일이 막무가내로 일어날 수 있다는 것이다.
그럼 여기서 callback을 통해 순서를 정할 수 있다.
위 함수를 아래와 같이 변경해보자!

const printString = (string, callback) => {
  setTimeout(
    () => {
      console.log(stirng)
      callback()
    },
    Math.floor(Math.random() * 100) + 1
  )}

const printAll = () => {
  printString('A', () => {
    printString('B', () => {
      printString('C', () => {})
    })
  })
}

printAll()

위와 같이 수정하면, 기존 const printString = (string) 에서 콜백함수를 추가로 더 인자를 받게 된다. 그러면 비동기적으로 일을 처리하겠지만, 순서를 지킬 수 있게 된다.

똑똑한 척하는 멍청이 '콜백지옥'

하지만 이러한 방법에 무수히 반복되게 되면 우리는 덫에 걸리고 만다. 바로 callbackHell이라는 덫에 말이다.

그러면 우리의 코드의 가독성은 최악으로 치닫게 되며, 추후에 수정할 때에도 매우 힘들어진다.

Promise 프로미스

그래서 코드의 가독성과 최적화를 이룬 Promise라는 방법을 통해 아래처럼 변경할 수 있다.

const printString = (string) => {
  return new Promise((resolve, reject) => {
    setTimeout(
      () => {
        console.log(string)
        resolve()
      },
      Math.floor(Math.random() * 100) + 1
    )
  })
}

const printAll = () => {
  printString('A')
  .then(() => {
    return printString('B')
  })
  .then(() => {
    return printString('C')
  })
}

printAll()

위의 방식으로 간편하게 변경할 수 있는데, 프로미스에 대해 아직 모르니 위의 코드를 보면서 알아보도록 하자!

Promise(callback, callback)

Promise는 비동기 함수로부터 내부처리를 통해 향후 사용할 값을 동기적으로 반환되는 객체이다. 그런데 내부처리를 통해 값을 얻을 수도 있고(Solved), 값을 얻지 못할 수도 있다(Rejected). 그리고 아직 처리가 되지 않았을(아직 값을 가지지 않은) 때는 Pending 상태이다.
Promise는 Fulfilled, Rejected, Pending 3가지 상태 중 하나를 가지는데, 내부처리를 통해 기대한 값을 가지게 되면 Fulfilled value 또는 Solved value를 가지게 되며, 그렇지 않은 경우 Rejected value를 가지게 된다.
Promise를 사용할 때에, fulfilled된 값을 다루는 콜백, 또는 rejected된 이유를 다루는 콜백을 (인자로) 첨부할 수 있습니다.

  • Fulfilled: onFulfilled()가 호출된다 (Ex. resolve() 호출)
  • Rejected: onRejected()가 호출된다 (Ex. reject() 호출)
  • Pending: 아직 fulfilled 또는 rejected 상태가 아님

조금 더 이해하기 쉽운 예시를 들면,

const someFunction = parameter => {
  return new Promise((resolve, reject) => {
    //do something with parameter and return result
    if(truthy) {
      return resolve(truthy result)
    } else {
      return reject(falthy result)
    }
  })
}

이렇게 무언가 내부처리를 통해서 값을 얻게 되면, truthy result한 값을 받게 되며, 그렇지 않으면 falthy result(일반적으로 error 코드 등)를 받게 된다.

그럼 해당 값이 바로 리턴 되느냐? 그렇지는 않다. 마치 bind처럼 해당 값을 묶어두고, 향후 호출할 때 리턴하기로 약속(promise)한다. 그리고 약속된 값을 불러오는 두 개의 메소드 .then, .catch가 있으며, 두 메소드는 반드시 콜백 함수를 인자로 받아야 한다.

someFunction(parameter)
// 위 함수 안에서 parameter를 통해 truthy한 값을 얻으면
// 해당 값은 아래 .then의 인자로 받게 된다.
  .then(truthy result => do something)
// 만약 falthy한 값을 얻으면
// .catch의 인자로 받게 된다.
  .catch(falthy result => do something)

0개의 댓글