9/26 TIL

정민세·2022년 9월 27일
0

비동기 (asychronous)

특정 코드의 연산이 끝날 때까지 코드의 실행을 멈추지 않고, 순차적으로 다음 코드를 실행하는 것 non-blocking 이라고도 한다. 하지만 Ajax로 데이터를 불러오기 전에 바로 다음 코드를 실행시켜 오류를 발생시킬 수 있다.

비동기의 3차례의 패러다임

비동기적으로 코드를 빠르게 실행시키고 싶지만 정해진 순차를 컨트롤 하기 위해 생겨난 문법들이다.

첫번째, Callback

  • Callback이란 제어권을 대상에게 넘겨주는 것이다.
  • 함수A의 매개변수로 콜백함수B를 전달하면 A가 B의 제어권을 갖게 된다.
  • 특별한 요청(bind)가 없는 한 A에 미리 정해진 방식에 따라 B를 호출한다.
const printString = (string, callback) => {   //printString이란 변수에 string과 callback함수를 파라미터로 받아온다.
  	setTimeout(				//JS 내장메소드로 있는 몇초 후에 값을 반환 할 것인지 정해준다.
      () => {
        console.log(string)			//string값을 console에 나타내주고
        callback()					// 콜백함수를 즉시 실행한다.
      },
      Math.floor(Math.random() * 100) + 1    //1~100까지 중에 정수를 랜덤하게 나타내고 소수점은 버린다.
    )
  }
      
      const printAll = () => {      //printAll이란 변수에 콜백함수를 실행
      	printString("A", () => {	//printString 함수를 불러와서 argument를 준다. 
          printString("B", () => {	//A라는 스트링과 콜백함수 호출로 A를 호출한 다음 B를 호출
            printString("C", () => {})	//B를 호출한 다음 C를 호출한다.
          })
        })
      }
      printAll()
  • 하지만 이런 무수한 콜백으로 인해 콜백지옥(CallbackHell)을 불러올 수 있다.
  • 이 문제를 해결하기 위해선 콜백 함수를 분리해주면 된다.

두번째, Promise

  • 비동기적으로 실행하는 작업의 결과(성공 or 실패)를 나타내는 객체
  • 비동기의 결과를 객체화 시킨다는 점이 Promise의 가장 큰 특징

Promise 생성자

생성자 함수와 동일하게 new로 Promise 객체를 만들 수 있다. 이 때 인자로는 Executor가 들어가는 데 Executor 는 resolve 와 reject 라는 두 개의 함수를 매개변수로 받는 실행함수이다. Executor 는 비동기 작업을 시작하고 모든 작업을 끝낸 후, 해당 작업이 성공적으로 이행이 되었으면 resolve 함수를 호출하고, 중간에 오류가 발생한 경우 reject 함수를 호출

var timeAttack = new Promise(function (resolve, reject) {
  setTimeout(function () {
    var ran = Math.random() * 10;
    if (ran >= 5) {
      resolve(ran);
    } else {
      reject();
    }
  }, 1000);
});

이 경우에 timeAttack 이라는 Promise 객체는 3가지 상태를 가진다.

대기(pending) : 아직 실행되지 않은 초기 상태
이행(fulfilled) : 작업이 성공적으로 완료됨.
거부(rejected) : 작업이 실패함.
작업이 성공적으로 이행이 되었거나, 실패 했을 때, 어떠한 작업을 해야 하는데 이 작업은 then 메소드에 의해 실행된다. 이는 callback함수를 실행한 것과 같은 효과를 낸다. then 메소드는 promise객체에 붙여서 사용한다.

timeAttack.then(function (num) {
  console.log(num + 'complete');
}, function () {
  console.log('error');
});
promise.then(successCallback, failureCallback) 이러한 방식으로 콜백을 실행할 수 있다.

then() Method
then 메소드는 promise객체를 리턴하고 두 개의 콜백 함수를 인수로 받는다. 사용 형태는 다음과 같다.

promise.then(successCallback, failureCallback)

promise.then(function (value) {
  //성공했을 때 실행
}, function (reason) {
  //실패했을 때 실행
});

위에 적은 successCallback 은 promise가 성공(fulfilled)했을 때를 위한 콜백 함수이고, failureCallback 은 실패(rejected)했을 때를 위한 콜백 함수이다.

chaining

then 메소드는 promise 객체를 리턴하고 인수로 받은 콜백 함수들의 리턴 값을 이어 받는다. 따라서 chaining이 가능하다. 아래의 예제처럼.

var promise = new Promise(function (resolve, reject) {
  setTimeout(function () {
    resolve(1);
  }, 1000);
});

promise.then(function (num) {
  console.log(num + 'complete'); /// 1complete
  return num + 1; /// return = 2
}).then(function (value) {
  console.log(value) // 2
});
resolve에 인자로 들어간 숫자 1이 첫번째 then() 메소드를 거치면서 +1이 되고 두번째 then() 메소드에서는 2가 되었다. 이처럼 promise를 리턴하는 then의 특성으로 계속해서 체이닝 패턴이 사용 가능하고, 값을 조작할 수 있다.

Callback Hell

Promise 이전의 비동기 처리는 Callback함수를 설정하는 방식으로 이루어졌다. 비동기가 완료되는 시점에 실행이 되는 callback함수로 완료를 인지하고 그 다음을 처리한 것이다. 그렇게 하다보니 비동기 처리를 연속적으로 해야하는 경우 Callback함수에 Callback함수가 들어가고 거기에 또 Callback함수가 들어가는 이상하고 요상한 코드가 되어 버렸다. 이것을 이른바 Callback Hell 이라고 한다.

a(function (resultA) {
  b(resultA, function (resultB) {
    c(resultB, function (resultC) {
      d(resultC, function (resultD) {
        //OMG.....
      });
    });
  });
});
Promise를 이용하여 이러한 Callback Hell을 말끔히 탈출할 수 있는 것은 아니지만 Callback을 함수로 바로 넘겨받지 않고 객체에 이어서 사용할 수 있게 되면서 훨씬 보기 쉬워졌다.

promise.then(function(a){
  
}).then(function(b){

}).then(function(c){

}).then(function(d){

});
profile
하잇

0개의 댓글