2-6.[JS/Node]비동기

들어가기 전

callback review

  • underbar sprint 참고

콜백의 의미

: 다른 함수의 전달인자로 넘겨주는 함수
: 파라미터를 넘겨받는 함수는 callback 함수를 필요에 따라

  • 즉시 실행할 수도 있고 아니면
  • 나중에 실행할 수도 있다

콜백함수의 종류

1)반복 실행하는 함수 : iterator
ex. map(callback)

2)이벤트에 따른 함수 : event handler
ex. addEventListener(callback)

콜백함수의 유의점

함수 그 자체를 붙이는 거지 함수의 실행을 붙이는 게 아니다!

handleClick의 실행 결과는 return값이 없어서 undefined가 되어 버린다!
아무튼 결과값을 넣는 거니까 실행X, 함수 그 자체를 붙인다

Blocking vs non-blocking

Blocking

ex. 전화

  • 하던 일을 멈추고 받아야 한다
  • 요청에 대한 결과가 동시에 일어난다 [동기적]

non-Blocking

ex. 문자

  • 확인 후 나중에 답장할 수 있다
  • 요청에 대한 결과가 동시에 일어나지 않는다 [비동기적]

커피 주문으로 알아보는 동기 vs 비동기

동기 : 요청에 대한 결과가 동시에 일어난다 (응답이 동기적으로 이뤄진다)
-> 즉 커피를 주문하면 커피 배달이 완료할 때까지 다음 사람의 주문조차 받을 수 없다

비동기 : 요청에 대한 결과가 동시에 일어나지 않는다
-> 즉 요청에 blocking이 없다 (주문을 모두 받고) 응답이 비동기적으로 이뤄진다
이벤트 (준비가 되었을 때 - 트리거가 생겼을 때) -> 이에 대한 핸들러 실행 (응답) : 콜백

요청 [call] - 완성 [event] - 응답[eventhandler : 콜백 ]

동기 함수

요소 하나하나에 대해 적용
1)console.log으로
2)2000, return coffee
=> 마십니다 - 접수되었습니다 - 2초 - 응답
=> 마십니다 - 접수되었습니다 - 2초 - 응답
request - sync(동기적으로) : waitSync - callback

비동기 함수

1)request + 가 접수되었습니다
2) 접수되었습니다
3)2000 이후 callback : customer.name 는 coffee를 마십니다
4) 마십니다

접수를 하고 callback이 나중에 실행된다

비동기 전달 패턴


1)콜백 패턴 : 다른 함의 인자로 비동기 함수를 받는
2)이벤트 핸들러 : 이벤트가 일어나면 함수 실행

비동기 주요 사례

  • DOM element의 이벤트 핸들러
    - 마우스, 키보드 입력
    • 페이지 로딩
  • 타이머
    - 타이머 API (setTimeout)
    • 애니메이션 API
  • 서버에 자원 요청 및 응답
    : url 등 서버를 통해서 정보를 얻어오는 것
    : 서버가 응답을 늦게 줘서 blocking이 일어나지 않도록 비동기적으로 요청을 일단 다 바든 것
    - fetch API
    - AJAX (XHR)

브라우저의 비동기 함수 작동 원리를 알려면

비동기 자바스크립트

왜 비동기

node.js: 비동기, without thread

클라이언트 : 서버로 접속하는 컴퓨터
서버 : 무언가 (서비스, 리소스 따위를) 제공하는 컴퓨터

동기 : 요청을 보내고 응답이 올 때까지 기다린다
비동기 : 요청을 하고 응답이 오기 전에 계속 다른 요청을 받거나 다른 일을 하고 있다

이전 기능이 다음 기능을 막지 않아서 non-blocking
가장 오래 걸리는 일만큼 걸리고 그 동안 다른 일들을 동시에 처리한다

ex. 유튜브 로딩
만약 동기면 로딩이 끝날 때까지 아무것도 할 수가 없음 - 화면을 끄고 다른 것을 요청할 수 있도록 한다

비동기는 동기와 달리 이전 일의 요청, 응답이 모두 끝나야 다음 일을 하는 것이 아니라 동시에 할 수 있게 하낟

callback

비동기 중 순서를 제어하고 싶은 경우에는 어떻게?
각각의 task가 요청된 순서와 달리 끝나는 시간이 다를 수 있으니까

응답 시간이 랜덤할 때 순서를 미리 예측할 수 없다
그래서 callback을 사용한다
callback : 비동기, 너 일 다 끝나면 이 일을 실행해 !

callback 안에서 다음 함수를 실행한다
즉 이전에 모든 응답을 한 다음에 callback 함수를 실행하는 것

실행만 하는 게 아니라 input을 통해 바꿔주기

callback을 인자로 받아서 사용하기도

callback은 좋은데 순차적으로 너무 많이 일어나면 가독서잉 떨어지고 관리하기 어렵다
=> callback hell

이걸 해결하기 위해 promise가 나타났다

promise

promise는 클래스다
new Promise를 통해 인스턴스를 만든다

  • resolve()
  • reject()

promise의 resolve에 다음 then에 있는 함수가 들어가서 결과값을 리턴하면 then의 data로 넘겨진다

이전에 return한 값을 다음 then에서 받는다

Promise란 콜백을 인자로 받지 않고
새로운 Promise 인스턴스를 리턴하는데
: 해당 인스턴스는 resolve, reject를 인자로 받는 인스턴스만의 콜백을 받는다
: resolve - 다음으로 넘긴다 (.then()을 사용할 수 있게 한다)
: reject - error 잡는다

함수 내에서 promise를 리턴한다
return new Promise를 통해 .then으로 다음에 일어나도록 한다
A 이후 콜백을 받는게 아니라 .then을 이용해서 앞이 끝나면 이후의 작업을 받는다는 의미
//동작은 콜백이랑 동일하게 동작이 된다

reject를 받았다면 마지막에 .catch를 통해 에러 핸들링을 한다
콜백 체인을 사용했다면 모든 단계에서 에러를 잡아줘야하지만 promise를 쓰면 마지막에 catch를 사용해서 바로 에러를 잡을 수 있다

하지만 Promise Hell도 가능

가독성, 유지보수 어려움??
어떤 문제가 생기는 건지?

이전 예시처럼 return을 매단계에 하면 이런 문제가 일어나지 않음
=> 리턴을 통해 프로미스 체이닝을 한다

promise chaining

promise.all

https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

Promise.all() 메서드
: 순회 가능한 객체에
1)주어진 모든 프로미스가 이행한 후,
2)혹은 프로미스가 주어지지 않았을 때
=> 이행하는 Promise를 반환합니다.

주어진 프로미스 중 하나가 거부하는 경우,
첫 번째로 거절한 프로미스의 이유를 사용해 자신도 거부합니다.

setTimerout의 세번째 매개변수는 첫번째 매개변수인 함수의 인자로 넘어간다
그러므로 resolve의 인자로 들어가서 conosle.log된다
promise3.then이 되는 거니까
Promise의 then으로 resolve에 console.log가 들어가서 console.log(foo)가 된다!

모두 끝나기를 기다린다음에 값을 하나하나
성공하면 resolve를 실행
setTimeout 때문에 100ms 후에 resolve를 실행하고 foo를 돌려준다

변수에 함수를 넣은 것. 실행한 게 아니라!
promise에 콜백함수 두개를 받는다

Promise.resolve(),
인자(콜백함수)를 then의 으로 넘기고

Promise.reject()로도 사용

async await

promise의 syntatic sugar
promise를 사용하는 것은 같은데 동기적인 것처럼 실행할 수 있다

async 함수라는 것을 표현하고
이후 await를 이용한다
=> 순서대로 실행된다

비동기 : callback chain < promise < promise chain < async await
callback chain은 callback 함수 내에서 다음 callback 함수를 소환한다
promise는 Promise 인스턴스에 resolve함수, reject함수를 인자로 넘겨서
.then으로 순서를 지정하고 마지막에 .catch로 에러를 잡는다
-> 이때 return을 안하면 HELL이 생기므로 매 단계에서 return을 하고 .then을 사용한다
async await는 비동기 함수라는 것을 async로 표현하고 callback 함수들 앞에 await를 이용해서 순서를 지정한다.


async 키워드 : 알아서 함수의 내용을 promise의 resolve()로 만들어준다
await : 뒤에 오는 코드가 다 실행될 때까지 기다린 다음 리턴한다 (async가 만든 promise에 대한 then)

async, await의 문제
: await를 바로 쓰면 각각 시간을 기다리므로 시간 낭비
그러므로 async 함수를 실행해 promise로 각각 만들어주는 함수를 만든 뒤 그 앞에 await를 써서 사용하면 시간 단축 가능???

위의 코드를 promise chaining으로 만드는 방법

타이머 API

setTimeout(callback, millisecond)

일정 시간 후에 함수를 실행

  • arguments : 실행할 callback 함수, callback 함수 실행 전 기다려야 할 시간(밀리초)
  • return value: 임의의 타이머 ID
setTimeout(function(){
console.log()
}, 1000);

setInterval(callback, millisecond)

일정 시간의 간격을 가지고 함수를 반복적으로 실행

  • arguments : 실행할 callback 함수, callback 함수 실행 전 기다려야 할 시간(밀리초)
  • return value: 임의의 타이머 ID
setInterval(function(){ 
	console.log()
}, 1000);

clearInterval(timerId)

반복 실행 중인 타이머를 종료

arguments: 타이머 ID
return value: 없음

const timer = setInterval(function(){ 
console.log();
}, 1000)
clearInterval(timer); 
// 더 이상 반복 실행되지 않음

setTimeout에 대응하는 clearTimeout도 있음

Sprint review

promise를 이용
bind를 쓴 이유
: setTimeout의 this가 전역이라서
함수를 실행 하는 것이 목적이 아니라 인자만 넘기기 위함

좋은 웹페이지 즐겨찾기