21.비동기 (callBack, Promise, async / await) - ES6

Updated:


1.callback

JS 는 항상 동기식 처리 (synchronous)

  • 동기식 처리가 뭐냐면 한번에 코드 한줄씩 차례차례 실행된다는 소리입니다.

  • 자바스크립트를 실행하는 웹브라우저는 stack이라는 코드 실행 공간이 있는데 거기서 코드를 한줄한줄 차례로 실행합니다.

예외의 경우 (asynchronous)

  • 단 예외로, 시간이 오래 걸리는 code 는 stack 에서 제외 시켜 web API 라는 곳에서 저장 시키고 나중에 code 를 실행 시킵니다 (ajax, setTimeout, eventLister 등)

  • 이런 처리방식을 바로 비동기(asynchronous)라고 합니다.

  • 실행이 오래걸리는 그런 코드들은 잠깐 대기실에 제쳐두고, 실행이 바로바로 가능한 코드들부터 처리하는 방식을 뜻합니다.

  • 이건 자바스크립트 언어 자체의 기능이 아니라 자바스크립트 실행을 도와주는 웹브라우저 덕분에 해낼 수 있는 것입니다.

image

잠깐 코드를 제쳐두는 대기실인 Web API

  • 실행을 미루고 옆으로 잠깐 제껴둘 수 있는 코드들은 미리 정해져있습니다. 위에서 말했던 setTimeout, addEventListener, ajax 관련 함수들이 바로 그것입니다.

  • setTimeout, addEventListener, ajax관련 함수들은 1초대기, 클릭대기 이런걸 하는 코드들인데이런 코드들의 특징은.. 읽는 시점과 동작 시점이 차이가 있습니다. (쉽게 말하면 동작까지 오래걸립니다.)

callback 함수를 이용한 순차적 실행

Q. 자바스크립트에서 1초 후에 코드를 실행하고 싶으면 어떻게 할까요?

console.log(1);
setTimeout(function(){
  console.log(2);
}, 1000);
console.log(3);

A. 그러면 콘솔창에 1과 3이 먼저 빠르게 출현하고 그 다음 1초 후에 2라는 숫자가 출현합니다.

  • 자바스크립트는 비동기상황 등에서 코드를 순차적으로 실행하고 싶을 때 콜백함수를 적극 활용합니다.

  • callback 함수란 쉽게 말해서 함수안에 들어가는 함수를 callback 함수라고 합니다.

  • 그러나 callback 함수가 많아지면 속칭, callback 지옥에서 빠져 코드를 읽을때 어려움이 있습니다.

first(function(){
  second(function(){
    thrid(function(){
      ... // 위와 같이 callback 함수의 연속은 좋은 code 가 아니게 됨
    });
  });
}):
  • 그렇게 때문에 callback 함수를 보기 좋게 하기 위해서 Promise 를 사용하게 됩니다.
first().then(function(){
   // second 에서 실행 할 코드
}).then(function(){
   // third 에서 실행할 코드 
});
  • Promise 를 사용하게 되면 좀 더 직관적으로 code 를 사용할 수 있습니다.

2.Promise

//  Promise 장점 : callback 함수와 비교해서 code 가 옆으로 길어지지가 않는다
let first = new Promise(function (resolve, reject) { // resolve 는 성공, reject 는 실패 한것을 나타냄
  resolve(); // resolve 가 실행이 되면 밑에 .then 이 실행이 됨
  reject(); // reject 가 실행이 되면 밑에 .catch 가 실행됨
});

first.then(() => {
  // first 가 성공일 경우 실행 할 코드
}).then(() => {
  // 그다음에 실행할 것
}).catch(() => {
  // catch 는 위의 코드가 실패 했을 경우 실행 하는 code
})

Promise 를 쓰는 이유

  • callback 대신 보기 좋은 코드

  • 성공, 실패의 경우에 맞춰 각각 다른 코드 실행 가능함

// Promise 예시 1.

let cal = new Promise(function (resolve, reject) {
  let sum = 1 + 1;
  resolve(sum); // 성공한 결과를 return 함
  
})

cal.then(function (result) {
  console.log(result)
}).catch(function () {
  console.log('fail')
})

Promise 의 3가지 상태

  • 성공하면 <resolved>

  • 판정 대기 중이면 <pending>

  • 실패하면 <rejected>

Promise 에 대한 오해

  • 비동기적 처리가 가능하게 바꿔주는 문법이 아닙니다. (단지, callback 함수대신해서 쓰기, 보기 쉽게 만들어주는 것임)

Promise 연습

Q. 이미지 로딩 성공시 특정 코드를 실행 하기

  • 이미지가 로드가 되면 콘솔 창에 성공, 실패를 출력함

  • Promise 를 사용해서 then, catch 함수를 사용해서 만들기

<!-- 아래의 이미지의 로드가 성공하면 '성공 메시지', 실패하면 '실패 메시지' -->
<img id="test" src="https://codingapple1.github.io/kona.jpg"> 
const LoadImg = new Promise((resolve, reject) => { // Promise 객체 생성
  const img = document.getElementById('test'); // img 변수에 HTML id 연결
  img.addEventListener('load', () => { // 로드 성공시  resolve() 실행
    resolve();
  });
  img.addEventListener('error', () => { // 로드 실패시 reject() 실행
    reject();
  });
});

LoadImg.then(() => { // 성공시
  console.log('성공');
}).catch(() => {  // 실패시
  console.log('실패'); 
})

3.async / await

  • ES8 문법에 Promise 를 대체할 async / await 키워드를 통해 쉽게 Promise 객체를 생성하고 then, catch 를 대신해서 사용할 수 있습니다.

  • asyncfunction 앞에 붙이면 함수가 Promise 역활을 하게 되는것임

  • 즉, async 를 function 앞에 붙이면 함수 실행 후에 Promise object 가 남게 되는 것입니다.

async function 안에 쓰는 await

  • then 대신에 사용이 가능한 await

  • 단순히 의미는 기다려 달라는 것인데 비동기적으로 처리를 할때 Promise 를 해결 할때 까지 기다리라는 의미 입니다.

  • 단! awaitasync 안에서만 사용할 수 있는 키워드 입니다

  • awaitPromise 가 실패 시 에러가 나고 멈춥니다.

  • 실패시 멈춤을 방지 하고자 try{} catch{} 구문을 사용합니다

try{} catch{}

async function cal() {
  let test = new Promise((resolve, reject) => {
    let sum = 1 + 1;
    resolve(sum);
  });

  try { //try 를 먼저 실행해보고 실행되면 try 문 그대로 출력
    let result = await test;
    console.log(result)
  } catch { // try 가 실패시, catch 문 출력
    console.log('fail')
  }
}

cal();

async / await 예제

  • Q. <button> 을 누르면 성공 판정 하는 Promise & 성공 시 ‘성공했어요 라고 출력하기’..
<button id="btn">btn</button>
async function cal() {
  const Btn = new Promise((resolve, reject) => {
    const button = document.getElementById('btn');
    button.addEventListener('click', () => {
      resolve('Pass');
    })
  });

  try {
    const result = await Btn;
    console.log(result);
  } catch {
    console.log('Fail')
  }
}


cal();
  • 순차적으로 많은 것을 실행 할때 유용 합니다 (async / await)

🔶 🔷 📌 🔑

Reference

Leave a comment