JavaScript:Promise
Promise는 비동기 작업의 최종 완료 또는 실패를 나타내는 객체입니다.
APIs
race
먼저 끝낸 Promise 를 반환한다.
reject
Promise.reject(reason) 메서드는 주어진 이유(reason)로 거부된 Promise 객체를 반환합니다.
Example:
Promise.reject("Testing static reject").then(function(reason) {
// 호출되지 않음
}, function(reason) {
console.log(reason); // "Testing static reject"
});
Promise.reject(new Error("fail")).then(function(error) {
// 호출되지 않음
}, function(error) {
console.log(error); // Stacktrace
});
오래된 콜백 API를 사용하여 Promise만들기
Promise는 생성자를 사용하여 처음부터 생성 될 수 있습니다. 이것은 오래된 API를 감쌀 때만 필요합니다.
이상적인 프로그래밍 세계에서는 모든 비동기 함수는 promise을 반환해야 하지만. 불행히도 일부 API는 여전히 success 및 / 또는 failure 콜백을 전달하는 방식일거라 생각합니다.. 예를 들면 setTimeout() 함수가 있습니다.
예전 스타일의 콜백과 Promise를 합치는것 문제가 있습니다. 함수 saySomething()이 실패하거나 프로그래밍 오류가 있으면 아무 것도 잡아 내지 않습니다. setTimeout()의 문제점 입니다.
다행히도 우리는 setTimeout()을 Promise로 감쌀 수 있습니다. 가장 좋은 방법은 가능한 가장 낮은 수준에서 문제가되는 함수를 래핑 한 다음 다시는 직접 호출하지 않는 것입니다.
const wait = ms => new Promise(resolve => setTimeout(resolve, ms));
wait(10000).then(() => saySomething("10 seconds")).catch(failureCallback);
기본적으로 promise constructor는 promise를 직접 해결하거나 reject 할 수 있는 실행자 함수를 사용합니다. setTimeout()은 함수에서 fail이 일어나거나 error가 발생하지 않기 때문에 이 경우 reject를 사용하지 않습니다.
Promise Timeout 만들기
결론부터 말하자면 다음의 순서로 진행하면 된다:
- 원래 수행할 작업을 Promise로 만든다.
- setTimeout에서 Exception을 내보내는 Promise를 만든다.
- 위의 두 Promise를 #race 함수로 호출한다.
waitInitialized(timeout?: number) {
const initPromise = this._initPromise.then((value: boolean) => {
if (!value) {
throw new Error();
}
return this.api;
});
if (typeof timeout !== 'undefined') {
return initPromise;
}
const timeoutPromise = new Promise((resolve, reject) => {
setTimeout(() => {
reject(new TimeoutError('An initialization timeout occurred'));
}, timeout);
});
return Promise.race([initPromise, timeoutPromise]);
}
중첩 Promise
Jest를 사용하여 다음의 코드를 테스트하면 ...
describe('playground', () => {
test('default', async () => {
console.debug('BEGIN --');
const aaa = new Promise((resolve, reject) => {
setTimeout(() => {
console.debug('resolve - before');
resolve(1);
console.debug('resolve - after');
}, 1000);
})
.then(() => {
console.debug('timeout done.');
})
.then(async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.debug('[INSIDE] reject - before');
reject('[INSIDE] reject call !');
console.debug('[INSIDE] reject - after');
}, 1000);
})
.then(() => {
console.debug('[INSIDE] timeout done.');
})
.catch(error => {
console.error(error);
});
})
.then(() => {
console.debug('next then');
})
.catch(error => {
console.error(error);
});
console.debug('Promise.all ...');
await Promise.all([aaa]);
console.debug('END --');
});
});
다음과 같은 결과가 나타난다.
BEGIN --
Promise.all ...
resolve - before
resolve - after
timeout done.
[INSIDE] reject - before
[INSIDE] reject - after
[INSIDE] reject call !
next then
END --
결론: 중첩으로 Promise 를 사용해도 결과가 잘 출력된다. 특히 14번째 줄의 async 함수를 사용해도 결국 Promise 의 재 중첩이 되므로 잘 실행된다.