Promise

Siwoo Pak·2021년 7월 26일
0

Javascript

목록 보기
23/34

1. promise란?

  • 비동기 작업의 최종 완료 또는 실패를 나타내는 객체.
  • 함수에 콜백을 전달하는 대신에, 콜백을 첨부하는 방식의 객체.
function successCallback(result) {
  console.log("Audio file ready at URL: " + result);
}

function failureCallback(error) {
  console.log("Error generating audio file: " + error);
}

createAudioFileAsync(audioSettings, successCallback, failureCallback);
  • 위와 같이 음성파일을 생성해주는 createAudioFileAsync()라는 함수가 있고, successCallback, failureCallback의 2개의 콜백함수를 받는 함수가 있다.
  • 위의 코드를 promise로 반환해주도록 수정해보면
createAudioFileAsync(audioSettings).then(successCallback, failureCallback);
// 아니면
const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);
  • 위와 같은 것을 비동기함수 호출이라고 부름

2.promise의 특징

  • call back은 자바스크립트 이벤트 루프가 현재 실행중인 call stack을 완료하기 이전에는 절대 호출되지 않음
  • 비동기 작업이 성공하거나 실패한뒤에 then()을 이요하여 추가한 콜백의 경우에도 위와 같음.
  • then()을 여러버 사용하여 여러개의 콜백 추가 할 수 있음
    그리고 각각의 콜백은 주어진 순서대로 하나하나 실행

3. promise의 상태

  • 대기(pending): 이행되거나 거부되지 않는 초기상태
  • 이행(fulfilled): 연산이 성공적으로 완료됨
  • 거부(rejected): 연산이 실패함

4. 용어

  • resolve: 주어진 값으로 이행
  • reject: 주어진 이유로 거부
  • then: 이행값 기록
  • catch: 거부 이유 기록

5.chaining

  • 순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우에
    promise chain을 이용함.
  • then() 새로운 promise를 반환하고, 처음에 만들었던 promise와는 다른 새로운 promise.
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
// promise와 promise2는 다른 놈.
// 다르게 표현하면
const promise2 = doSomething().then(successCallback, failureCallback);
  • promise2는 domSomething()뿐만 아니라 성공할때와 실패할때의 콜백함수의 완료를 의미함.
  • 2개의 콜백함수 또한 promise를 반환하는 비동기 함수일수도 있음.
  • 이 경우엔 Promise2에 추가된 콜백은 successCallback 또는 failureCallback에 의해 반환된 promise 뒤에 대기함.
  • 기본적으로 각각의 promise는 체인 안에서 서로 다른 비동기 단계의 완료를 나타냄
  • 예전에 콜백함수로만 이루어진 코드
doSomething(function(result) {
  doSomethingElse(result, function(newResult) {
    doThirdThing(newResult, function(finalResult) {
      console.log('Got the final result: ' + finalResult);
    }, failureCallback);
  }, failureCallback);
}, failureCallback);
  • promise를 이용한다면
doSomething().then(function(result) {
  return doSomethingElse(result);
})
.then(function(newResult) {
  return doThirdThing(newResult);
})
.then(function(finalResult) {
  console.log('Got the final result: ' + finalResult);
})
.catch(failureCallback);
  • then()에 넘겨지는 인자는 선택적임
  • 그리고 catch(failureCallback)은 then(null, failureCallback)의 축약.
  • 위의 코드를 화살표함수로 나타내면,
doSomething()
.then(result => doSomethingElse(result))
.then(newResult => doThirdThing(newResult))
.then(finalResult => {
  console.log(`Got the final result: ${finalResult}`);
})
.catch(failureCallback);

6. Chaining after a catch

  • chain에서 작업이 실패한 후에도 새로운 작업을 수행하는 것이 가능함
new Promise((resolve, reject) => {
    console.log('Initial');

    resolve();
})
.then(() => {
    throw new Error('Something failed');

    console.log('Do this');
})
.catch(() => {
    console.log('Do that');
})
.then(() => {
    console.log('Do this, whatever happened before');
});
  • 위의 코드를 실행하게 되면, 다음과 같이 텍스트가 콘솔에 나옴
Initial
Do that
Do this, whatever happened before
  • 첫번째 then() new Error()가 reject를 호출, catch()가 실행됨.

7. Error propagation

  • 콜백함수의 경우 콜백마다 에러함수를 호출했는데, promise chain 한 번만 호출함.
  • 기본적으로 promise chain은 예외가 발생하면 멈추고 chain의 아래에서 catch를 찾습니다. 이것은 동기코드가 어떻게 동작하는지 모델링 한 것.
try {
  const result = syncDoSomething();
  const newResult = syncDoSomethingElse(result);
  const finalResult = syncDoThirdThing(newResult);
  console.log(`Got the final result: ${finalResult}`);
} catch(error) {
  failureCallback(error);
}
  • 위의 코드를 async/await구문으로 바꾼다면,
async function foo() {
  try {
    const result = await doSomething();
    const newResult = await doSomethingElse(result);
    const finalResult = await doThirdThing(newResult);
    console.log(`Got the final result: ${finalResult}`);
  } catch(error) {
    failureCallback(error);
  }
}
  • async와 await는 promise를 기반으로 함.
  • promise는 모든 오류를 잡아내어, 예외 및 프로그래밍 오류가 발생해도 콜백지옥의 근본적인 결함을 해결함. 이는 비동기 작업의 기능 구성에 필수적.

8.promise rejection events

  • promise가 reject될 때마다 2가지 이벤트 중하나가 전역 범위에 발생(전역범위는 window이거나 웹워커에서 사용되는 경우, worker 혹은 worker 기반 인터페이스)
  • 전역범위에 발생되는 이벤트
    • rejectionhandled
      • executor의 reject()에 의해 reject가 처리 된후 promise가 reject될 때 발생함.
    • unhandledrejcetion
      • promise가 reject되었지만 사용할 수 있는 reject핸들러가 없을 때 발생함.
  • 위의 이벤트들은 멤버변수인 promise와 reason 속성이 있음.
    • promise: reject된 promise를 가리키는 속성
    • reason: promiserk reject된 이유를 알려주는 속성
  • 이들을 이용해 프로미스에 대한 에러처리를 대체하는 것이 가능해짐
  • 또한 프로미스 관리시 발생하는 이슈들을 디버깅하는데 도움을 얻을 수 잇음.
  • 이 핸들러들은 전역적이기 때문에 모든 에러는 발생한 지점에 상관없이 동일한 핸들러로 전달됨.
  • unhandlerejection 이벤트 핸들러를 사용한 예
window.addEventListener("unhandledrejection", event => {
  /* You might start here by adding code to examine the
     promise specified by event.promise and the reason in
     event.reason */

  event.preventDefault();
}, false);

9.오래된 콜백api를 사용하여 promise 만들기

  • promise는 생성자를 사용하여 처음부터 생성가능
  • 이것은 오래된 api를 감쌀 때만 필요함
  • setTimeout()를 예를 들어
setTimeout(() => saySomething("10 seconds passed"), 10000);
  • 예전 스타일의 콜백과 promise를 합치는 것은 문제가 있음
  • 함수가 실패하거나 프로그래밍 오류가 있으면 아무것도 잡아내지 않기 때문에.
  • 하지만 promise로 setTimeout() 래핑 가능
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));

wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);

참고

profile
'하루를 참고 인내하면 열흘을 벌 수 있고 사흘을 참고 견디면 30일을, 30일을 견디면 3년을 벌 수 있다.'

0개의 댓글