[TIL]200921 Asynchronous & Promise-1

Chaegyeom·2020년 9월 24일
0

TIL

목록 보기
39/77
post-thumbnail

두 개의 문자열을 매개변수로 받아 공통으로 가지고 있는 문자를 순서대로 return하는 함수를 작성하세요. (공백, 중복 제외)

예시

commonCharacters('acexivou', 'aegihobu'); //결과 : 'aeiou'

재귀로 풀 수 있을 것 같은데 아직 재귀에 대한 공부가 부족해서 그런지 이중 반복문으로 풀어냈다
비교나 반복을 할 것 같으면 반복문 부터 작성하는 나 자신에 대해서 반성해야 되겠다.

Asynchronous

Asynchronous는 무엇일까? Asynchronous는 비동기적인, 동시에 존재[발생]하지 않는이라는 뜻이다
그럼 비동기적인 작업은 왜 필요할까?

클라이언트와 서버가 있을 때 동기적인 작업과 비동기적인 작업을 그림으로 나타내 봤다.

동기적인 작업(Synchronous)
1. 클라이언트가 어떤 요청을 보낸다
2. 서버가 요청을 받아서 일처리를 한다
3. 클라이언트가 기다린다
4. 서버에서 응답(response)이 오면 처리를 시작한다

비동기적인 작업(Asynchronous)
1. 클라이언트에서 서버로 어떤 요청을 보낸다
2. 서버가 작업을 하는 동안 클라이언트는 기다리지 않고 다른 작업들을 한다(continue working)
3. 서버에서 작업을 마치고 응답(response)이 오면 응답(response)을 가지고 다른 작업들을 한다

그리고 이런 비동기적인 작업처리 방식은 전체 작업시간을 단축할 수 있다.

Asynchronous에서 순서 제어

Async가 좋다는 것은 알겠는데 그럼 순서는 어떻게 제어할 수 있을까?
아래 예제를 보자

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

printString이라는 함수는 setTimeout메소드를 통해 랜덤시간 이후에 입력된 stringconsole.log로 찍어준다.
이 함수를 printAll 이라는 함수로 A, B, C를 묶어서 실행하게 되면 어떻게 될까?

위와 같이 매번 랜덤한 순서대로 실행될 것이다.
이런 랜덤한 순서가 아니고 A > B > C 순으로 실행하고 싶다면 어떤 방법이 있을까?

Callback

첫 번째 방법은 callback이다

const printString = function(string, callback) {
    setTimeout(function(){
        console.log(string)
        callback()
      }, 
      Math.floor(Math.random() * 100) + 1
    )
  }
 
  const printAll = () => {
    printString("A", function(){
      printString("B", function() {
        printString("C", function(){})
      })
    })
  }

콜백을 통해 다음 함수를 실행 하는 방법이다 위의 방법을 사용하면

위와 같이 순서대로 나오게 된다

Callback방식에서 에러를 handling하는 방법

작업을 처리하다 보면 분명히 에러가 있을텐데 callback방법에서는 어떻게 에러를 핸들링 할 수 있을까?
인자로 data와 error가 함께 들어오기 때문에 조건문(if)를 통해서 에러일때는 데이터인자를 null로 바꿔줘야 하고 에러가 아닌경우에는 error인자를 null로 바꿔주어야 한다

  fs.readFile(filePath, "utf8", function (err, data) {
    if (err) {
      callback(err, null);
    } else {
      callback(null, data);
    }
  });

callback방식의 문제점

callback을 통해 비동기함수를 제어할 때 문제점이 있다. 바로 callback이 많아지는 경우에 가독성이 떨어지게 되는데, 이것을 callback hell이라고 부른다
만들어 보자면 아래와 같다

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

보기만해도 읽기 싫어지는 코드다

Promise

콜백헬을 벗어나기 위한 하나의 테크닉으로 Promise가 있다
promise는 하나의 클래스와 같은 것으로 new promise를 통해서 인스턴스가 만들어진다

위에서 봤던 callback방식의 printString함수이다

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

  const printAll = () => {
    //왠지 여기서 부터 callback hell이 일어날 것만 같은 느낌적인 느낌
    printString("A", () => {
      printString("B", () => {
        printString("C", () => {})
      })
    })
  }
  printAll() // now what do you expect?

주석 이후부터 뭔가 callback hell이 일어날 것만 같다

Promise는 콜백을 인자로 받지 않고 새로운 promise 인스턴스를 리턴하는데 promise는 promise만의 callback을 받는다 resolve와 reject를 인자로 받는 callback을 받는다

위의 callback방식을 promise방식으로 바꿔보면 아래와 같다

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

  const printAll = () => {
    //callback보다 평평해졌다!
    printString("A")
    .then(() => {
      return printString("B")
    })
    .then(() => {
      return printString("C")
    })
  }
  printAll()

callback과 동일한 결과를 리턴하지만 callback hell보다 평평해서 가독성이 좋아진다
promise는 task가 끝나고나서 .then을 통해 다음 task를 이어갈 수 있다

또한 callback은 매번 에러처리를 해줘야 하지만 promise는 마지막에 .catch를 통해 에러를 한번에 핸들링 할 수 있다

promise도 hell이 있다?

return처리를 제대로 해주지 않을 경우 아래와 같이 hell이 생성된다

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

function sitAndCode() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('2. sit and code') }, Math.floor(Math.random() * 100) + 1)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('3. eat lunch') }, Math.floor(Math.random() * 100) + 1)
    })
}

function goToBed() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('4. goToBed') }, Math.floor(Math.random() * 100) + 1)
    })
}

gotoCodestates()
.then(data => {
    console.log(data)

    sitAndCode()
  //뭔가 또 hell인 것 같다...
    .then(data => {
        console.log(data)

        eatLunch()
        .then(data => {
            console.log(data)
            
            goToBed()
            .then(data => {
                console.log(data)
        
            })
        })
    })
})

최근 새로나온 async/await

es8에 추가되었다
async/await는 promise인데 보이는 모습이 조금 다른 것이라고 볼 수 있다
awatit를 통해서 비동기 함수들을 마치 동기적인 함수처럼 사용할 수 있다.

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

function sitAndCode() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('2. sit and code') }, Math.floor(Math.random() * 100) + 1)
    })
}

function eatLunch() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('3. eat lunch') }, Math.floor(Math.random() * 100) + 1)
    })
}

function goToBed() {
    return new Promise((resolve, reject) => {
        setTimeout(() => { resolve('4. goToBed') }, Math.floor(Math.random() * 100) + 1)
    })
}

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, promise와 동일한데 표현을 동기적으로 할 수 있기 때문에 코드 가독성이 높아진다

profile
주니어 개발자가 되고싶은

0개의 댓글