3 minute read

동기와 비동기

동기 (Synchronous)

  • 작업 완료 시점과 작업 시작 시점이 같다
  • 앞의 작업이 완료 돼야 다음 작업이 시작될 수 있다.
console.log('1st');
console.log('2nd');
console.log('3rd');

 코드는 동기적인 실행을 거친다.
첫번째 코드가 먼저 실행되고,  실행이 끝나면 두번째 코드가 실행,
 실행이 끝나면 세번째 코드가 실행되어 순서대로 '1st', '2nd', '3rd'  찍힌다.
앞의 코드의 실행이 끝날때까진 다음 코드가 실행될  없다.
이것이 동기 (Synchronous)이다.

비동기 (Asynchronous)

  • 작업 완료 시점과 작업 시작이 같지 않아도 된다.
  • 앞의 작업이 완료되지 않아도 다음 작업을 시작할 수 있다.
console.log('1st');
  setTimeout (() => {
    console.log('2nd');
  }, 0);
console.log('3rd');

 코드로 비동기 함수가 실행되는 메커니즘을 설명할  있다.
setTimeout() method를 이용해 지연시간을 0초로 줬으므로,
순서대로 '1st', '2nd', '3rd' 찍힐것 같지만, 실제로는
'1st', '3rd', '2nd' 찍히게 된다.
 이유는, setTimeout이라는 함수가 비동기라는 것을 인지한 프로그램이
비동기 API를 처리하는 프로그램에 넘겨버린다.
그리고 작업을 처리하는 스택에 '1st'  쌓인  출력, '3rd' 쌓인  출력되고,
스택의 모든 작업이 처리되되고 비워지면 API를 처리하는 프로그램에서 작업이 끝난 '2st'
스택에 쌓인  출력된다. 

동기와 비동기의 예

동기는 치킨집을 방문한 남훈이가 치킨을 주문하고, 그 치킨이 나올때 까지 뒤에있는 종서는 주문을 할 수 없다.

이를 blocking라고 부른다. 앞의 작업이 끝날 때까지 뒤의 작업들을 막는 것이다.

반면 비동기는, 남훈이가 치킨을 주문한 뒤 치킨이 나오면 받으러 오기로 하고, 뒤에있던 종서가 이어서 바로 주문을 한다. 앞의 작업이 끝날 때까지 blocking을 하지 않으므로, 효율적인 task 처리가 가능하다.

Callback

  1. 다른 함수의 매개변수로 들어갈 수 있는 함수.
  2. 어떤 이벤트가 실행됐을때 호출되는 함수
const test1 = (callback, num) => callback(num)

const test2 = (num) => num + 2;
  

console.log(test1(test2, 10)); // 12

위 코드처럼, test1의 첫번째 인자로 callback함수 test2, 두번째 인자로 num 10을 전달하고,

결국 test2(10)을 리턴한다. test2(10)을 실행하면 10 + 2 → 12가 결과로 나온다.

이것이 콜백함수이다.

하지만, 어떤 작업을 하다보면, callback이 쌓여 가독성에 아주 좋지 않은 코드가 될 때가 있다.

바로 위와 같은 경우이다.

이것을 Callback Hell이라고 한다. 말 그대로 콜백 지옥.

이 지옥에서 빠져나가기 위해 우리는 Promise라는 것을 알아야 한다.

Promise

  • new Promise()를 사용한다
  • new Promise()의 첫번째 인자는 resolve, 두번째 인자는 reject를 넣어준다.
  • 성공적으로 불러왔다면 resolve() 의 값이 전달, ex) resolve(‘hi’)
  • 문제가 생겼다면 reject()의 값이 전달된다. 이때 new Error을 사용. ex) reject(new Error(‘err..’))
// (3) test함수가 실행된다
const test = (num) => {
  return new Promise((resolve, reject) => {
    setTimeout(() => {
// (4) 인자로 전달받은 1을 찍는다.
      console.log(num);
      resolve();
// (5)1000ms (1초)의 간격.
    }, 1000)
  })
}

const testRun = () => {
// (2) test 함수에 인자를 1로 전달하고 실행한다.
  test(1)
// (6) 위의 test(1) 함수의 실행이 끝나면, (.then)
  .then(() => {
// (7) test 함수에 인자를 2로 전달하고 실행한다. 이후 반복.
    return test(2)
  })
// (8) 위의 test(2) 함수의 실행이 끝나면, (.then)
  .then(() => {
// (9) test 함수에 인자를 3으로 전달하고 실행한다.
    return test(3)
  })
}

// (1) 제일 처음 testRun 함수 실행
testRun(); // (10) (1초 간격으로) 1, 2, 3

얘보다 더 깔끔하게 사용하기 위해서, Async await이라는걸 사용한다.

Async await

const test = (num) => {
  return new Promise((resolve, reject) =>
    setTimeout(() => {
      console.log(num);
      resolve();
    }, 1000)
  })
}

const testRun = async () => {
  await test(1);
  await test(2);
  await test(3);
}

testRun(); // (1초 간격으로) 1, 2, 3

기존 promise 코드와 같지만, 호출하는 함수에서 함수명을 async로 지어주고,

일반 함수를 호출하는 것처럼 호출하면 된다. 단, 앞에 await을 붙여준다.

async와 await은 짝궁이다.

타이머 API

  • setTimeout(callback, millisecond)
    • 일정 시간 (두번째 인자 millisecond) 후에 함수를 실행한다.
    • 인자 : 실행할 callback 함수, callback함수 실행 전 기다릴 시간을 전달
    • 리턴 : 임의의 타이머 ID
      setTimeout(() => {
        console.log('1초 후에 실행됩니다');
      }, 1000);
    
      // (1초 뒤) 1초 후에 실행됩니다
    
  • setInterval(callback, millisecond)
    • 일정 시간 (두번째 인자 millisecond)을 가지고 함수를 반복적으로 실행한다.
    • 인자 : 실행할 callback 함수,반복적으로 함수를 실행시키기 위한 시간 간격을 전달
    • 리턴 : 임의의 타이머 ID
      setInterval(() => {
        console.log('1초마다 실행됩니다');
      }, 1000);
    
      // (1초마다) 1초마다 실행됩니다
    
  • clearInterval(timerId)
    • 반복중인 타이머를 종료한다.
    • 인자 : 타이머 ID
    • 리턴 : 리턴하지 않음
      // 위에서 1초마다 실행되는 타이머의 아이디가 1일때
      clearInterval(1)
      // 그녀석의 반복을 중단한다.
    

Node.js 모듈

  • 비동기 이벤트 기반 자바스크립트 런타임.
  • 로컬 환경에서 자바스크립트를 실행할 수 있다.
  • 브라우저에서 불가능한 몇가지 일들이 가능하다.

Node..js 모듈 불러오기

→ 코드 가장 상단에 requre를 이용해 불러온다.

const fs = require('fs') // file system 모듈을 불러온다
const dns = require('dns') // DNS 모듈을 불러온다

3rd-party 모듈 (써드 파티 모듈) 사용하기

→ 얼마전 공부했던 underscore (우리에겐 underbar)는 Node.js에서 공식적으로 제공하는 빌트인 모듈이 아닌, 써드파이 모듈이다. 이런 모듈들을 사용하기 위해서는 npm을 이용해야한다.

npm install underscore를 입력해 underscore를 다운받고, 위에서 했던 방식대로 모듈을 불러오면 된다.

const _ = require('underscore')

Updated: