Promise는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체이다.
기본적으로 promise는 함수에 콜백을 전달하는 대신에, 콜백을 첨부하는 방식의 객체이다.
promise는 프로미스가 생성된 시점에는 알려지지 않았을 수도 있는 값을 위한 대리자로,
비동기 연산이 종료된 이후에 결과 값과 실패 사유를 처리하기 위한 처리기를 연결할 수 있다.
프로미스를 사용하면 비동기 메서드에서 마치 동기 메서드처럼 값을 반환할 수 있다.
다만 최종 결과를 반환하는 것이 아니고, 미래의 어떤 시점에 결과를 제공하겠다는 '약속'을 반환한다.
대기 중인 프로미스는 값과 함께 이행될 수도, 어떤 이유(오류)로 인해 거부될 수도 있다.
이행이나 거부될 때, 프로미스의 then 메서드에 의해 대기열(큐)에 추가된 처리기들이 호출된다.
이미 이행했거나 거부된 프로미스에 처리기를 연결해도 호출되므로, 비동기 연산과 처리기 연결 사이에
경합 조건은 없다.
Promise()
새로운 Promise 객체를 생성한다.
주로 프로미스를 지원하지 않는 함수를 감쌀 때 사용한다.
비동기로 음성 파일을 생성해주는 createAudioFileAsync() 라는 함수가 있다고 생각해보자.
해당 함수는 음성 설정에 대한 정보를 받고, 두 가지 콜백 함수를 받는다. 하나는 음성 파일이
성공적으로 생성되었을 때 실행되는 콜백, 그리고 다른 하나는 에러가 발생했을 때 실행되는 콜백이다.
createAudioFileAsync()는 아래와 같이 사용된다.
funcion 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() 함수가 Promise를 반환하도록 수정한다면, 다음과 같이
간단하게 사용될 수 있다.
createAudioFileAsync(audioSettings).then(successCallback,failCallback);
조금 더 간단하게 써보자면
const promise = createAudioFileAsync(audioSettings);
promise.then(successCallback, failureCallback);
우리는 이와 같은 것을 비동기 함수 호출이라고 부른다. 이런 관례는 몇 가지 장점을 가지고 있다.
1) Guarantees
콜백 함수를 전달해주는 고전적인 방식과는 달리, Promise는 아래와 같은 특징을 보장한다.
Promise의 가장 뛰어난 장점 중 하나는 chaining이다.
2) Chaining
보통 두 개 이상의 비동기 작업을 순차적으로 실행해야 하는 상황을 흔히 보게 된다. 순차적으로 각각의 작업이 이전 단계 비동기 작업이 성공하고 나서 그 결과값을 이용하여 다음 비동기 작업을 실행해야 하는 경우를 의미한다. 우리는 이런 상황에서 promise chain을 이용하여 해결하기도 한다.
then() 함수는 새로운 promise를 반환한다. 처음에 만들었던 promise와는 다른 새로운 promise이다.
const promise = doSomething();
const promise2 = promise.then(successCallback, failureCallback);
또는
const promise2 = doSomething().then(successCallback, failureCallback);
두 번째 promise는 doSomething()뿐만 아니라 successCallback 이나 failureCallback의 완료를 의미한다. successCallback 이나 failireCallback 또한 promise를 반환하는 비동기 함수일 수도 있다. 이 경우 promise2에 추가된 콜백은 successCallback 또는 failureCallback에 의해 반환된 promise 뒤에 대기합니다.
기본적으로, 각각의 promise는 체인 안에서 서로 다른 비동기 단계의 완료를 나타낸다.
예전에는 여러 비동기 작업을 연속적으로 수행하면 지옥의 콜백 피라미드가 만들어졌었는데
우리는 콜백 함수들을 promise에 promise chain을 형성하도록 추가하면 이를 해결할 수 있다.
doSomething(function(result) {
doSomethingElse(result, function(newResult) {
doThirdThing(newResult, function(finalResult) {
console.log('Got the final result: ' + finalResult);
}, failureCallback);
}, failureCallback);
}, failureCallback);
// 위 코드를 아래와 같이 바꿀 수 있다.
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);
단, 반환값이 반드시 있어야한다, 만약 없다면 콜백 함수가 이전의 promise의 결과를 받지 못한다.
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');
});
그러면
Initail
Do that
Do this, whatever happend before
출력된다. 여기서 Do this가 출력되지 않는데 이는 Somthing failed 에러가 rejection을 발생시켰기 때문이다.
https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Global_Objects/Promise
https://developer.mozilla.org/ko/docs/Web/JavaScript/Guide/Using_promises