Asynchronous & Promise

김민석·2021년 3월 15일
0

Immersive

목록 보기
16/30

들어가며....

이번의 주제는 비동기적 함수의 순서 제어 방법이라고 생각하면 될 것 같다.

물론 비동기적인 것이 동기적인 것보다 실행 속도가 빠를 수 밖에 없지만, 때로는 이 순서들을 제어해야하는 경우가 있을 것이다.

그런 경우에 그 순서를 제어하는 방식.

즉, 어떤 함수가 모두 실행된 후에 이어지는 함수가 실행되도록 제어하는 방법에 대해 배운다.

const printString = (string) => {
    setTimeout(
      () => {
        console.log(string)
      }, 
      Math.floor(Math.random() * 100) + 1
    )
  }

  const printAll = () => {
    printString("A")
    printString("B")
    printString("C")
  }
  printAll() // what do you expect?

위 예시의 경우 A,B,C는 random 한 순서로 콘솔에 찍힌다.
setTimeout에 의해 비동기적으로 실행되기 때문이다.

Callback

우선 콜백을 이용하여 위 문제를 해결할 수 있을 것 같다.
로직은 다음과 같다.

printString 함수를 정의할 때,
특정 시간 이후에 arg에 들어온 string을 콘솔에 찍도록 하고,
직후에 콜백 함수를 실행하도록 만드는 것이다.

예시

const printString = (string, callback) => {
    setTimeout(
      () => {
        console.log(string)
        callback()
      }, 
      Math.floor(Math.random() * 100) + 1
    )
  }

  const printAll = () => {
    printString("A", () => {
      printString("B", () => {
        printString("C", () => {})
      })
    })
  }
  printAll() // now what do you expect?

아래는 callback 함수를 활용하여 error를 핸들링 하는 방법이다.

조건을 지정하여, 경우에 따라 콜백 함수에 인자를 다르게 전달하는 식으로 진행한다.
(아래 나올 resolve, reject와 비슷)

Callback error handling Desing

const somethingGonnaHappen = callback => {
    waitingUntilSomethingHappens()

    if (isSomethingGood) {
        callback(null, something)
    }

    if (isSomethingBad) {
        callback(something, null)
    }
}

Usage

somethingGonnaHappen((err, data) => {
    if (err) {
        console.log('ERR!!');
        return;
    }
    return data;
})

Promise🤬🤬🤬

promise.... 이름은 뭔가 달콤(?)하지만 그 맛은 매우 쓰다. 자세하게 짚고 넘어가는 것이 좋을 것 같다.

promise란?

우선 promise는 어떠한 생성자에 의해 만들어진 instance 들을 의미한다.
뭐, 줄여서 말하자면 promise는 객체다.

그런데 좀 특별한 객체다.
promise는 콜백을 전달하는 '대신', 콜백을 첨부하는 방식의 객체라고도 볼 수 있다.

이것이 사용되는 이유는

비동기 연산이 종료된 이후의 결과값이나 실패 이유를 처리하기 위한 처리기를 연결할 수 있도록 하기 위함이다.

이 promise는 세 가지 상태를 가진다.

  • 대기
  • 이행
  • 거부

참고 1:
promise 객체의 속성/프로토타입/정적 메서드 / 인스턴스 메서드
MDN 링크

thenable : 메서드 .then을 가진 객체를 모두 thenable 객체라고 부른다. 이 객체는 promise와 같은 방식으로 처리된다. (출처)

참고 2:
Promise.prototype.then()에 대하여.

then()methods는 promise를 리턴하며, promise가 이행, 거부 될 각각의 경우에 대응하는 callback function들을 인자로 갖는다.

then의 Parameters

onFulfilled 함수와 onRejected 함수 모두 각각 하나의 인자만을 갖는다.

onFulfilled는 정의되지 않을 시 identitify func으로 대체,
onRejected는 Trower func으로 대체


then의 return value

각각의 onFulfilled나 onRejected(이하 핸들러 함수)는 특정한 규칙을 따라 작동한다. 규칙과 예시/MDN

그 중 몇 가지 기억하고 싶은 것을 적어보겠다.

  • then handler가 특정 value를 리턴한다면
    Promise.resolve(value)로 리턴함.
var p2 = new Promise(function(resolve, reject) {
  resolve(1);
});

p2.then(function(value) {
  console.log(value); // 1
  return value + 1;
}).then(function(value) {
  console.log(value + ' - A synchronous value works'); // 2 - A synchronous value works
});

p2.then(function(value) {
  console.log(value); // 1
});

  • then이 error을 throw하거나, rejected Promise를 리턴한다면 rejected promise를 리턴함.
Promise.resolve()
  .then(() => {
    // Makes .then() return a rejected promise
    throw new Error('Oh no!');
  })
  .then(() => {
    console.log('Not called.');
  }, error => {
    console.error('onRejected function called: ' + error.message);
  });

  • 만약 onFulfilled 함수가 promise를 리턴한다면, return value는 해당 promise 객체에 의해 resolved/rejected 된 결과를 리턴한다.
function resolveLater(resolve, reject) {
  setTimeout(function() {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(function() {
    reject(new Error('오류'));
  }, 1000);
}

var p1 = Promise.resolve('foo');
var p2 = p1.then(function() {
  // 1초 뒤에 10으로 이행할 프로미스 반환
  return new Promise(resolveLater);
});
p2.then(function(v) {
  console.log('이행', v);  // "이행", 10
}, function(e) {
  // 실행되지 않음
  console.log('거부', e);
});

var p3 = p1.then(function() {
  // 1초 뒤에 '오류'로 거부할 프로미스 반환
  return new Promise(rejectLater);
});
p3.then(function(v) {
  // 실행되지 않음
  console.log('이행', v);
}, function(e) {
  console.log('거부', e); // "거부", '오류'
});

0개의 댓글