[TIL] Asynchronous & Promise

Ha Young Do·2021년 5월 17일
0

Asynchronous Javascript

  • synchronous: 동기적인 요청 처리, 하나의 요청이 처리되어야지만 다음 요청을 이어서 받을 수 있다. 시간이 많이 소요되는 요청의 경우 처리가 끝날 때까지 다른 작업을 할 수 없는데, 이 때문에 하나의 요청에 browser가 막혀 있는 상황을 blocking이라 칭한다.
  • asynchronous: 비동기적인 요청 처리, 하나의 요청을 보내 놓은 동안 다른 작업을 처리할 수 있어 효율적이다.
  • JavaScript는 한 번에 하나의 작업만 처리되는 single-threaded programming language이기 때문에 한 번에 여러 개의 작업을 처리하기 위해서는 asynchronous 문법을 사용해야 한다.

Promise

Promise란?

-> 비동기 작업의 성공 혹은 실패, 그리고 return값을 표현하는 객체. 다음과 같이 세 가지 상태 중 하나를 가진다:

  • 대기(pending): 이행하거나 거부되지 않은 초기 상태.
  • 이행(fulfilled): 연산이 성공적으로 완료됨.
  • 거부(rejected): 연산이 실패함.
const promise = new Promise((resolve, reject) => {
    if (some condition is true) {
        resolve('You did it!');
    } else {
        reject('Better luck next time!');
    }
});
 
promise
    .then((message) => {
        console.log(message); // 성공(resolve)한 경우 실행 
    })
    .catch((error) => {
        console.error(error); // 실패(reject)한 경우 실행 
});
  1. new Promise() 라는 instantation method로 Promise 객체를 생성한다.
  2. 생성된 Promise 객체 안에 resolve와 reject를 매개변수로 갖는 callback function을 인자로 넣어준다.
  3. 이렇게 만들어진 promise에 .then 혹은 .catch method를 chaining해서 실행할 수 있다.
  4. promise 내부에서 resolve가 호출되면 then이 실행되고, reject가 호출되면 catch가 실행된다.
    • resolve와 reject에 넣어준 인자는 각각 then과 catch의 매개변수에서 받을 수 있다.
    • finally() method의 경우 연산의 성공 실패 여부와 관계 없이 실행된다.
    • 세 가지 method 전부 새로운 promise 객체를 return한다.
promise
    .then(message => {return something})
    .then(something => {return somethingElse})
    .then(somethingElse => {return somethingCompletelyDifferent})
    .catch(error => {console.error(error)});
  1. then이나 catch에 다시 다른 then이나 catch를 chaining 할 수 있다.
    • 앞에 chaining 된 then 혹은 catch의 return값인 promise 객체를 인자로 받아 실행된다.
    • 이 때 예외적으로 특정한 경우에 error handling을 개별적으로 처리하고 싶은 게 아니라면 여러 개의 then을 chaining 해 준 후 마지막에 단일 catch로 마무리한다.
    • 위와 같은 경우 중간의 어느 then에서 에러가 발생하더라도 바로 catch에서 에러를 받아 handling 해 줄 수 있다.

Callback Hell

$.get('url', function (response) {
    parseValue(response, function (id) {
        auth(id, function (result) {
            display(result, function (text) {
                console.log(text);
            });
        });
    });
});

Promise라는 새로운 문법을 사용하지 않고 async 처리를 설계하는 방법 중에는 callback function을 사용하는 방법도 있다. 다만 callback안에 callback을 호출하고, 또 그 안에서 callback을 호출하는 식으로 작업을 이어 주기 때문에 가독성이 떨어지고 유지보수가 어려운 단점이 있다.

Promise.all

let p1 = Promise.resolve(3);
let p2 = 1337;
let p3 = new Promise((resolve, reject) => {
  setTimeout(() => {
    resolve('foo');
  }, 100);
});

Promise.all([p1, p2, p3]).then(values => {
  console.log(values); // [3, 1337, 'foo']
});
  • 여러 개의 promise 객체를 array로 묶어서 Promise.all() method에 인자로 넣어 주면 각각의 promise의 이행값을 하나의 array로 묶어 return하는 새로운 promise 객체를 return한다.
  • 인자로 들어간 promise 객체 중 하나라도 reject될 경우 Promise.all()이 return하는 promise 객체 또한 reject된다. (전부 resolve일 경우에만 Promise.all()도 resolve)

Async/Await

async function demonstrateAsyncAwait {
  let p1 = await Promise.resolve(3);
  let p2 = 1337;
  let p3 = await new Promise((resolve, reject) => {
    setTimeout(() => {
      resolve('foo');
    }, 100);
  });
  
  console.log([p1, p2, p3]); // [3, 1337, 'foo']
}
  1. async keyword를 함수 앞에 붙여 async function으로 만들어 준다. 이 경우 일반 함수가 promise 객체를 return하는 async function이 된다. 이 경우 다른 asynchronous한 함수와 동일하게 .then() 등의 chaining이 가능하다.

  2. async function 내부에 await keyword를 사용할 수 있다. promise 객체 혹은 비동기 함수 앞에 await keyword를 붙여 해당 promise가 이행될 때까지 코드를 멈추고 기다린다.

  3. async/await 문법을 사용하는 경우 try...catch로 error handling을 한다.

async function demonstrateAsyncAwait {
  try {
    let p1 = await Promise.resolve(3);
    let p2 = 1337;
    let p3 = await new Promise((resolve, reject) => {
      setTimeout(() => {
        resolve('foo');
      }, 100);
    });

    if (somethingIsWrong) {
      throw new Error('Hey, it's an error!');
    }

    return[p1, p2, p3]; // [3, 1337, 'foo']
  } catch(e) {
  	console.log(e) // 'Hey, it's an error!'
  }
}

throw keyword는 에러를 코드 읽는 것을 멈춘다. catch로 throw을 받아서 error handling을 한다. return은 함수가 정상 실행되고 종료되었음을 알리는 키워드로 이후 코드를 정상적으로 실행한다.

Event Loop & Task Workflow

-> 비동기 처리를 가능하도록 하는 browser의 기능

  • Stack
    작성한 코드가 stack에 차례로 push되어 실행되고, 실행이 끝나면 pop되어 나온다. 만약 실행될 코드가 비동기문이라면 (setTimeout, ajax(), promise, click event 등) background로 넘겨져서 비동기 실행을 한다.

  • Callback Queue
    background에서 모두 이행되어 나온 실행문은 callback queue에 들어가 stack이 비기를 기다린다. (promise 혹은 thenable method들은 job queue에서 대기한다.)

  • Event Loop
    event loop은 계속 실행되면서 stack에 쌓인 실행문이 있는지 확인하고, stack이 비어 있을 때 callback queue를 확인하여 실행문이 있다면 queue에서부터 pop하고 stack에 push하여 실행되도록 한다.

https://backback.tistory.com/319
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
https://developer.mozilla.org/en-US/docs/Learn/JavaScript/Asynchronous/Async_await
https://medium.com/@Rahulx1/understanding-event-loop-call-stack-event-job-queue-in-javascript-63dcd2c71ecd

profile
Codestates Software Engineering Full IM 28th

0개의 댓글