CallBack / Promise / Async

Front-end Dev. Hyuk·2020년 9월 22일
0

Asynchronous JavaScript

목록 보기
2/3


영상의 있는 내용을 가져와 적어보았다.

순서를 제어하고 싶은 경우엔 어떻게 해야하는 것인가를 예로 들고 설명을 했다.

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

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

실행을 하게 되면 Math.random으로 끝나기 때문에 차례대로 나오지 않고 random으로 나오는 것을 볼 수 있다. 그래서 순서를 제어하고 싶은 경우 어떻게 해야 될 것인가로 callback이 나왔으며 다음과 같이 볼 수 있다.
async(비동기)를 Handle 할 수 있는 고마운 녀석으로 생각하면 된다.
즉 비동기가 얼마나 걸릴지 모르겠지만 그 일 다 끝나면 이것을 실행해 다음과 같이 제어가 가능하다는 것이다.

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

const printAll = () => {
    printString("A", () =>{ // A를 받아서 callback을 해주고 있다.
        printString("B", () => { // 이 callback 함수 안에서 또 다른 String B를 실행해주며
            printString("C", () => {}) // 이 callback에서 c를 실행해준다.
        })
    })
}
printAll()

코드를 작성한 것을 보면 아까랑 다르다는 것을 알 수 있다.
두번째 인자로 callback을 넣었으며, setTimeout이라는 것에서 callback을 해주기 때문이다. 또한 PrintString("A", () =>{ 안에 arrow function으로 다 B와 C가 들어가 있는 것을 알 수 있다.
이렇게 순차적으로 진행이 되면서 A,B,C가 나오는 것을 알 수 있다.
그래서 callback이 우리한테 참 고마운 것을 알 수 있게 해준다.

// Callback error handling Design
const somethingGonnaHappen = callback => {
    waitingUntilSomethingHappens() // callback에다가 인자를 넘겨주려고 작성한것이다.

    if (isSomethingGood) {
        callback(null, something)
    } // 잘 되서 오면 callback에 앞에 null을 넣어주고 someting을 넣어주게 만들었고
    if (isSomethingBad) {
        callback(error, null)
    }// 만약에 잘 안되면 error을 넣어주어 error가 나오게 하고 null 대신 data를 넣어 data를 나오게한다.
}

// Usage(용법)
somethingGonnaHappen((err, data) => {
    if (err) {
        console.log('ERR!!');
        return;
    }
    return data;
}); // 즉 다음과 같이 err, data를 넣어 만약 err일시 err가 나오게 한다 그게 아니면 data가 나오게 만든다.
// 사용자를 고려해서 callback으로 잘 전달되게 사용하며 앞에를 err, 뒤에는 data를 넣어주는 경우가 많다.
// 앞으로 API, library 등 가져다 쓰게되면 err를 앞에쓰고 data를 뒤에 쓰게되는 경우가 많을 것이다.

이렇게 사용했지만 callback도 단점이 있다. callback으로 불러오게 되면 결국 길어지기 때문에 이 또한 문제가 많아서 다른 방법이 탄생하게 되었는데 그게 바로 Promise라는 것이다.

Callback -> Promise

함수를 만들 때 callback을 인자로 받지 않고 return을 하는데 새로운 Promise로 instance 한다.

Promise만의 callback을 받으며 resolve와 reject라는 인자를 받아서 실행하게 된다.

//callback ->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") // 비동기함수로 B로 실행할수있다
    })
    .then(() => { // B가 끝나면 .then으로 또 이어나갈 수 있다.
        return printString("C")
    })
} // C 비동기 작업을 끝나고 종료가되게 한다. 만약 여기에 reject가 있다면 .catch로 처리가능하다.
printAll()

callback을 인자로 받는 것이 아닌 .then으로 이어 나갈 수가 있다.
뒤에 callback함수를 받으며 끝나면 다음 작업을 해줘 라는 것과 같다.

그 전과 비교해보면 가독성이 좋아 보인다.

How to deal with callback chain.
기존에 callback에서 err 처리하는 것을 만들어주고 err 처리를 할때마다 작성을 해야하지만 promise는 마지막 chain에 .catch 처리를 함으로써 간단하게 정리가 가능해졌다.

매회 err 핸들링을 안해줘서 편하진 것이다.

하지만 Promise에서도 마찬가지로 Promise Hell이 나온다.

function gotoCodestates() {
  return new Promise((resolve, reject) => {
      setTimeout(() => {resolve('1. go to codestates') }, 100)
  })
}

function sitAndCode() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve('2. sit and code') } ,100)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve('3. eat lunch') }, 100)
    })
  }
  
function goToBed() {
      return new Promise((resolve, reject) => {
          setTimeout(() => {resolve('4. goToBed') } ,100)
      })
}

  gotoCodestates()
  .then(data => { // 어떤 data를 가져왔고 밑에 보면 sitAndCode를 또 시동걸린다.
      console.log(data)

      sitAndCode()
      .then(data => { // 또 data 받아와서 또 받아오면서 또 가져온다.
          console.log(data)

          eatLunch()
          .then(data => { // 또 받고 
              console.log(data)

              goToBed()
              .then(data => { // callback처럼되는것을 볼수있다.
                  console.log(data)
              })
          })
      })
  })

그래서 우리는 Promise Chaining을 통해서 해당 비동기를 다시 비동기로 넘기면 전체 .then()에 다음으로 올수 있게 한다.

기존의 Promise로 평평하고 가독성 좋으며 callback형태를 피할수 있다.

function gotoCodestates() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {resolve('1. go to codestates') }, 100)
    })
  }
  
  function sitAndCode() {
      return new Promise((resolve, reject) => {
          setTimeout(() => {resolve('2. sit and code') } ,100)
      })
  }
  
  function eatLunch() {
      return new Promise((resolve, reject) => {
          setTimeout(() => {resolve('3. eat lunch') }, 100)
      })
    }
    
  function goToBed() {
        return new Promise((resolve, reject) => {
            setTimeout(() => {resolve('4. goToBed') } ,100)
        })
  }
  
gotoCodestates()
.then(data => {
    console.log(data)
    return sitAndCode()
})
.then(data => {
    console.log(data)
    return eatLunch()
})
.then(data => {
    console.log(data)
    return goToBed()
})
.then(data => {
    console.log(data)
})

최근에는 async await라는 ES7인가 8에서 사용 되는 것이 있다. (node ver이 높으면 사용할 수 있다.)

Promise로 보이는 모습이 다른 것을 볼 수 있으며 동기로 보이지만 비동기 적인 것을 볼 수 있다.

function gotoCodestates() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('1. go to codestates') }, 100)
    })
}

function sitAndCode() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('2. sit and code') }, 100)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('3. eat lunch') }, 100)
    })
}

function goToBed() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('4. goToBed') }, 100)
    })
}

const result = async () => {
    const one = await gotoCodestates();
    console.log(one)

    const two = await sitAndCode();
    console.log(two)

    const three = await eatLunch();
    console.log(three)

    const four = await goToBed();
    console.log(four)
}

result();

callback은 실행코드안에 실행했지만 지금은 일반함수처럼 쓰이고 있는것을 볼 수 있으며 결과 값으로 받아올 수 있는 것을 확인할 수 있다.

굉장히 평평하고 마치 일반함수처럼 실행되어있고 동기적으로 보이지만 비동기적이며 사용시 함수 앞에는 async가 반드시 들어가야한다.

profile
The Known is finite The unknown is infinite.

0개의 댓글