[POB#18] Core Javascript 1 동기, 비동기 (ft. cb, Promise, async, await )

dongwon·2021년 8월 12일
1

원티드-프리온보딩

목록 보기
12/25
post-thumbnail

8월 12일 수업을 이해한 대로 정리한 글입니다.

동기, 비동기에 대한 이해

컴퓨터의 프린트 기능을 예를 들었습니다.

동기적

프린트 하기를 눌렀을 때 프린트가 다 될 때까지 컴퓨터로 어떠한 동작도 할 수 없다.
즉, 현재 진행 중인 코드가 끝나야 다른 코드를 실행합니다.

장점

task 실행 순서가 보장됩니다.

단점

task 블로킹. 즉, 현재 실행 중인 task가 종료될 때까지 다음 task가 실행이 안됩니다.

task가 블로킹 되는 이유
Javascript 엔진은 Single Thread 이기 때문에 하나의 task만 처리할 수 있습니다. 따라서 동시에 처리할 수 없어 한 task가 오래 걸리면 블로킹이 걸리게 됩니다.

alert("확인 눌러야 task 종료. 안 누르면 블로킹!!");
console.log("alert 확인 눌러야 찍힙니다.");

비동기적

프린트 하기를 누름과 동시에 컴퓨터로 다른 작업을 할 수 있다.
즉, 현재 실행 중인 코드가 완료되지 않아도 다음 코드로 넘아갑니다. ( 비동기 task는 브라우저가 처리하고, 다음 task 실행 )

장점

task 블로킹이 발생하지 않습니다.

단점

task 실행 순서가 보장되지 않습니다.

콜백 함수 ( callback, cb )

함수의 매개변수가 함수일 때, 매개변수로 받은 함수를 콜백 함수라고 합니다.
간단하게 비동기 처리를 할 수 있습니다.

window.addEventListener("keydown", (e) => {
  // 이벤트를 인자로 받는 콜백함수
  // keydown 시 비동기 처리를 할 로직 부분
});
setTimeout(function () {
  // 매개변수를 익명함수로 받은 콜백함수
  alert("Hello");
}, 3000);

모든 콜백 함수가 비동기 처리를 하는 건 아니다.

단순히 곧바로 어떤 동작을 할 때 콜백 함수는 동기적으로 작동합니다.

function showMessage(msg, closeFn) {
  // cb : closeFn
  closeFn(true);
}

// cb : el * 2
[1, 2, 3].map((el) => el * 2);

고차 함수

매개변수를 함수로 받은 함수. 위의 showMessage나 Aarray.map과 같은 함수.

콜백 지옥

콜백 함수를 연달아 작성해 들여 쓰기가 깊어지는 현상을 말합니다.

step1(function (value1) {
  step2(function (value2) {
    step3(function (value3) {
      step4(function (value4) {
        // 더 깊이..
      });
    });
  });
});

Promise

비동기 동작을 처리하기 위한 ES6 문법 ( 콜백 지옥 탈출하기 위해! )

promise 객체 구현

Promise는 클래스라 인스턴스 하여 promise 객체를 구현해야 합니다.
resolvereject 함수를 이용해 성공, 실패했을 때의 로직을 구현할 수 있습니다.
promise.then을 이용해 resolve 함수와 reject 함수를 정의할 수 있습니다.

let promise = new Promise(function (resolve, reject) {
  // 임시로 temp가 treu면 성공, false면 실패라고 했을 때,
  if (temp) {
    resolve("성공");
  }
  reject(new Error("실패"));
});

promise.then(
  function (msg) {
    console.log(meg); // 성공
  },
  function (err) {
    console.log(err); // 실패
  }
);

Promise Chaining

비동기 작업에 실행 순서가 필요할 때, 예를 들어 이전 비동기 작업의 결과물을 이용해 다음 비동기 작업을 실행하는 경우 사용합니다.

사용법

첫 번째 비동기 처리 함수에서 return 값을 다음 비동기 작업의 결과물로 넘길 수 있습니다. 넘겨진 결과물은 다시 .then의 callback 함수의 인자로 받아 사용할 수 있습니다.

let promise = new Promise(function(resolve,reject){
    resolve(1);
})

promise.
    then(funciton(first)){
    console.log(first)
    return first + 1
    }.then(function(second)){
    console.log(second)
    // return second + 1...
}

promise를 return 했다면 ?

중간에 promise를 return 했다면 다음 then은 return된 promise에 대한 resolve 함수 입니다.

promise
    ...
	.then(function(second) {
		console.log('second', second);

		return new Promise(function(resolve, reject) {
        setTimeout(function() {
            resolve(3);
        }, 1000);
    });
	})
	.then(function(third) {
		console.log(third); // 3
	});

Promise 에러 처리

reject() 함수promise.catch로 처리합니다.

let promise = new Promise(function (resolve, reject) {
  reject(new Error("에러 !"));
});

promise
  .then(function () {
    // 이쪽으로 안가고 catch로 이동
  })
  .catch(function (err) {
    console.log(err); // 에러 !
  });

Promise의 3가지 상태

Pending (대기) : 비동기 처리 로직이 아직 완료되지 않은 상태
Fullfilled (이행) : 비동기 처리가 완료되어 프로미스가 결과 값을 반환해준 상태
Rejected (실패) : 비동기 처리가 실패하거나 오류가 발생한 상태

// 크롬 브라우저 개발자 모드에서 실행하면 상태가 나옵니다.
let promise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    console.log("before", promise); // Pending 상태
    if (temp) {
      resolve(1);
      console.log("1", promise); // Fullfilled 상태
    }
    // temp가 false라면,
    reject(2);
    console.log("2", promise); // Rejected 상태
  }, 1000);
});

Promise.all

여러 비동기 작업을 처리한 후 비동기 처리를 하고 싶을 때 사용합니다.

Promise.all([
  new Promise((resolve) => setTimeout(() => resolve(1), 9000)), // 1
  new Promise((resolve) => setTimeout(() => resolve(2), 2000)), // 2
  new Promise((resolve) => setTimeout(() => resolve(3), 1000)), // 3
]).then(console.log());

async, await

비동기 처리를 Promise 보다 쉽게 사용할 수 있습니다.
ES8 문법으로 async를 이용해 비동기 함수를 선언하고, await를 이용해 실행 순서를 보장받을 수 있습니다.

사용법, 예외 처리

async 키워드를 이용해 비동기 함수라고 선언을 해줍니다. 그 후 함수 안에 동기적 처리를 해야 하는 부분에 await 키워드를 이용해 설정합니다.
예외 처리를 위해 try, catch 문을 이용합니다.

(async () => {
  try {
    let productResponse = await fetch("https://api.test.com/proudcts");
    let firstProductId = productResponse.products[0].id;

    let commentResponse = await fetch(
      "https://api.test.com/proudct/comments?id=" + firstProductId
    );
    let firstCommentId = commentResponse.comments[0].id;
  } catch (error) {
    console.log(error);
  }
})();
profile
데이원컴퍼니 프론트엔드 개발자입니다.

0개의 댓글