immersive TIL #10

paxkk·2020년 8월 10일
0

Synchronous와 Asynchronous JavaScript

Synchronous는 동기적인 이라는 뜻으로 위에 그림에서 예를 들면 클라이언트가 서버에 요청을 보내면 서버에서 데이터를 가공하거나 다른 작업을 할 때 클라이언트는 그동안 가만히 있다가 다시 서버에서 리스폰이 올 경우 다시 작동하는 원리이다.

Asynchronous는 비동기적이라는 뜻으로 정반대의 뜻이다 서버에 요청을 보내도 그동안 다른 작업을 수행 할 수 있으며 서버에게 응답이 오면 다시 작업을 진행한다.

동기적일 경우 시간이 한가지 작업이 끝나면 다음 작업을 진행 할 수 있기때문에 시간이 더욱 오래 걸리겠지만
비동기적일 경우 동시에 작업을 진행 할 수 있기 때문에 시간이 적게 걸린다.

callback

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

  const printAll = () => {
    printString("A", () => {             //콜백함수안에서 다음 부분이 실행된다.
      printString("B", () => {           //마찬가지로 콜백함수안에서 printString를 실행
        printString("C", () => {})
      })
    })
  }
  printAll() // now what do you expect?

콜백은 async를 핸들할 수 있다. 다시 요청해달라는 의미로비동기적인 일이 끝나면 다시 콜백으로 넘겨주는것을 실행하는것이다.
위 코드에서 printString함수는 두번째 인자로 콜백을받았다.콜백함수를 사용 안할 시에는 A,B,C가 랜덤으로 나오고 위와 같이 콜백함수를 사용한다면 A,B,C가 순차적으로 나올 것이다.

allback 에서의 error

const somethingGonnaHappen = callback => {
    waitingUntilSomethingHappens()

    if (isSomethingGood) {
        callback(null, Good)       
    }

    if (isSomethingBad) {
        callback(Bad , null)
    }
}

일반적으로 앞에는 에러 뒤에는 데이터(원하는 결과 값)을 작성한다.

somethingGonnaHappen((err, data) => {
    if (err) {                     //에러가 있을경우
        console.log('ERR!!');
        return;
    }
    return data;                   //없을 경우에는 결과값을 반환한다.
})

callback hell


콜백이 적을경우엔 상관없겠지만 이런식으로 많아지게 된다면 가독성도 좋지않고 코드를 관리하기 어려움이 많을 것이다. 그래서 등장한것이 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(() => {                 //.then으로 순차적으로 실행
      return printString("B")      
    })
    .then(() => {
      return printString("C")
    })
  }
  printAll()

함수 내에서 프로미스를 리턴하고 .then뒤에 콜백을 넘기면 순차적으로 A가 끝나면 비동기적으로 printString B 가 실행되고 그다음에 C 부분이 실행된다. 동작은 콜백과 동일하지만 정갈해서 가독성이 좋다.

또한, 콜백에서 에러처리를 할 경우 콜백을 할 때 마다 에러처리를 일일히 다 해주어야하지만
promise에서는 에러 핸들링을 .catch으로 마지막 체이닝에서 할 수 있다.

promise 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()
    .then(data => {
        console.log(data)

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

promise Chaining

promise hell도 call back헬과 마찬가지로 일어날 수 있다.
그래서 promiseChaining를 사용하면 좀더 깔끔하게 나타내고 콜백을 피할 수 있다.
아래와 같이 return을 통해서 다음 비동기를 넘겨준다.

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)
    return sitAndCode()
})
.then(data => {
    console.log(data)
    return eatLunch()
})
.then(data => {
    console.log(data)
    return goToBed()
})
.then(data => {
    console.log(data)
})

async와 await

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

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

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

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

const result = async () => {                    //함수앞에 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();

promise와 동일하게 동작하지만 표현을 동기적으로 쓸 수 있어서 코드 가독성이 높아진다.
await를 사용해 비동기 함수들을 동기적인 프로그램인것처럼 쓸 수 있다.
setTimeout 을 이용해 시간을 500,400,300,200 순으로 줬지만 순서는 gotoCodestates부터 순서대로 콘솔에 출력된다.

setTimeout을 0초로 주는 경우는 스택이 비어있을때까지 기다리게 하기위해서 0초를 주는것이다.

eventloop

콜스택과큐 webapi, eventloop 비동기 함수가 호출되는 방식에대한 이해를 돕기위한 영상
https://www.youtube.com/watch?time_continue=1024&v=8aGhZQkoFbQ&feature=emb_title

profile
꾸준하게 성장하자

0개의 댓글