[JS]비동기 호출

nada_1221·2022년 7월 26일
0

공부

목록 보기
18/49

개요

비동기 쉽게 이해하기


카페에서 커피를 주문하려고 줄을 서는 모습을 상상해 보자.
카페의 사정상, 커피를 주문한 먼저 온 김코딩이 주문한 커피를 받을 때까지, 줄 서 있는 박해커가 주문조차 할 수 없다고 하자. 이를 blocking이라고 부른다. 하나의 작업이 끝날 때까지, 이어지는 작업을 막는 것이다.

박해커는 김코딩이 주문한 커피가 나오고 나서야 커피를 주문할 수 있다. 김코딩의 커피 주문 완료 시점과 박해커의 커피 주문 시작 시점이 같다. 이렇게 시작 시점과 완료 시점이 같은 상황을 동기적synchronous라고 한다.

효율적인 카페 운영을 위해서 아래와 같이 카페의 주문 과정을 변경해 보자.

  • 커피 주문이 blocking되지 않고, 언제든지 주문을 받을 수 있다.
  • 커피가 완성되는 즉시 커피를 제공한다,
    • 김코딩의 주문 완료 시점과 박해커의 주문 시작 시점이 같을 필요가 없다.

Node.js를 만든 개발자도 위 대안이 합리적이라고 생각했다. 그래서 Node.js를 non-blocking하고 비동기적asynchronous로 작동하는 런타임으로 개발하게 된다.

JS의 비동기적 실행Asynchronous execution이라는 개념은 웹 개발에서 특히 유용하다. 특히 아래 작업은 비동기적으로 작동되어야 효율적이다.

  • 백그라운드 실행, 로딩 창 등의 작업
  • 인터넷에서 서버로 요청을 보내고, 응답을 기다리는 작업
  • 큰 용량의 파일을 로딩하는 작업

비동기 호출

Asynchronous call

callback review

  • 다른 함수(A)의 전달인자argument로 넘겨주는 함수 (B)
    • parameter를 넘겨받는 함수 (A)는 callback함수(B)를 필요에 따라 즉시 실행synchronously할 수도 있고, 아니면 나중에asynhronously 실행할 수도 있다.
function B(){
  console.log('called at the back!');
}

function A(callback){
  callback(); // callback === B
}

A(B);

callback in action : 반복 실행하는 함수 iterator

[1,2,3].map(function(ele,idx){ 
  //3회 반복 = idx만큼 반복
  return ele*ele;
});

callback in action : 이벤트에 따른 함수event handler

document.querySelector('#btn').addEventListner('click', function(e){
  console.log('button clicked');
});

헷갈리지 말자!


function handleClick(){
  console.log('button clicked');
};
documnet.querySelector('#btn').onclick = handleClick; //OK

documnet.querySelector('#btn').onclick =function(){
  handleClick();
} //OK

documnet.querySelector('#btn').onclick =handleClick.bind(); // OK

documnet.querySelector('#btn').onclick =handleClick(); 
//NO --> 함수 실행을 연결하는 것이 아니다. 함수 자체를 연결하는 것이다.
//handleClick() 은 return 값이 없기 때문에 결과 값은 undefined가 나온다.

blocking vs. non-blocking


전화문자
하던일을 멈추고 밥다야 한다. (blocking)확인 후, 나중에 답장할 수 있다. (non-blocking)
요청에 대한 결과가 동시에 일어난다. (synchronous)요청에 대한 결과가 동시에 일어나지 않는다. (asynchronous)

커피 주문으로 알아보는 동기 vs. 비동기
동기 : 요청에 대한 결과가 동시에 일어난다.

만일 커피 주문이 동기적으로 작동한다면?

  1. 손님 1이 아메리카노를 주문한다.
  2. 접수를 받은 직원이 아메리카노를 내린다.
  3. 직원이 손님 1에게 아메리카노를 전달한다.
  4. 손님 2가 카페라떼를 주문한다.
  5. 접수를 받은 직원이 카페라떼를 만든다.
  6. 직원이 손님 2에게 카페라떼를 전달한다.

이 중에서 잘 못된 것은?
왜 따로 주문받고 만드는가 --> 동시에 주문 받고 순차적으로 뽑으면 되는 거 아닌가?
--> 손님 2가 카페라떼를 주문한다.
: 손님2는 손님1이 아메리카노를 전달 받을때 까지 주문도 하지 못하고 대기열에 머물러 있어야 한다.

비동기

  1. 손님 1이 아메리카노를 주문한다.
    1. 접수를 받은 직원이 아메리카노를 내린다.
    2. 아메리카노가 완성되면 직원이 손님 1을 부른다.
    3. 아메리카노를 손님 1에게 전달한다.
  2. 손님2가 카페라떼를 주문한다.
    1. 접수를 받은 직원이 카페라떼를 만든다.
    2. 카페라떼가 완성되면 직원이 손님 2를 부른다
    3. 카페라떼를 손님 2에게 전달한다.

완성되면 <-- callback

<동기함수로 만든 커피 주문 코드>

function waitSync(ms) {
  let start = Date.now();
  let now = start;
  while (now - start < ms) {
    now = Date.now();
  }
}
// 현재 시작과 시작 시각을 비교하며 ms 범위 내에서 무한 루프를 도는 blocking 함수이다.

function drink(person, coffee) {
  console.log(person + "는" + coffee + "를 마십니다");
}

function orderCoffeeSync(coffee) {
  console.log(coffee + "가 접수되었습니다.");
  waitSync(2000); //<-- 2sec pause
  return coffee;
}

let customers = [
  {
    name: "Steve",
    request: "cafe latte",
  },
  {
    name: "John",
    request: "Americano",
  },
];

//call synchronously
customers.forEach(function (customers) {
  let coffee = orderCoffeeSync(customer.request);
  drink(customer.name, coffee);
});

//cafe latte 가 접수되었습니다.
//Steve는 cafe latte를 마십니다.
//Americano가 접수되었습니다.
//John는 아메리카노를 마십니다.

<비동기 함수로 만든 커피 주문 코드>

function waitSync(callback, ms) {
  setTimeout(callback, ms);
  //특정 시간 이후에 callback 함수가 실행되게끔 하는 브라우저 내장 기능.
}

function drink(person, coffee) {
  console.log(person + "는" + coffee + "를 마십니다");
}

let customers = [
  {
    name: "Steve",
    request: "cafe latte",
  },
  {
    name: "John",
    request: "Americano",
  },
];

function orderCoffeeASync(menu, callback) {
  console.log(menu + "가 접수되었습니다");
  waitASync(function () {
    callback(menu);
  }, 2000);
}

//call asynchronously
customers.forEach(function (customers) {
  orderCoffeeASync(customer.request, function (coffee) {
    drink(customer.name, coffee);
  });
});

//caffe latte가 접수되었습니다.
//Americano 가 접수되었습니다.
//Steve는 caffe latte를 마십니다.
//John는 Americano를 마십니다.

비동기 함수 전달 패턴 1 : callback 패턴

let request = 'caffelatte';
orderCoffeeAsync(request, function(response){
  //respnse -> 주문한 커피 결과
  drink(response);
});

비동기 함수 전달 패턴 2 : 이벤트 등록 패턴

let request = 'caffelatte';
orderCoffeeAsync(request).onready=function(response){
  //respnse -> 주문한 커피 결과
  drink(response);
};

비동기의 주요 사례

    > DOM Element의 이벤트 핸들러
  • 마우스, 키보드 입력(click, keydown 등) => DOM 세션
  • 페이지 로딩 (DOMContentLoaded 등) => DOM 런코 Noe
    > 타이머
  • 타이머 API (setTimeout 등) => Timer API 세션
  • 애니메이션 API(requestAnimationFrame) => 직접 찾아보자
    > 서버에 자원 요청 및 응답
  • fetch API => 서버에 요청하기 세션
  • AJAX(XHR) => 직접 찾아보자

브라우저의 비동기 함수 작동 원리를 알려면 (advanced)
Event Loop
Philip Roberts: Help, I'm stuck in an event-loop

profile
FE_개발자_지망생

0개의 댓글