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 의 재 중첩이 되므로 잘 실행된다.