수색…
통사론
- 새로운 약속 (/ * 실행자 함수 : * / function (해결, 거부) {})
- promise.then (onFulfilled [, onRejected])
- promise.catch (onRejected)
- 약속. 해결 (해결)
- Promise.reject (이유)
- Promise.all (iterable)
- Promise.race (iterable)
비고
약속은 ECMAScript 2015 사양의 일부이며 브라우저 지원 은 제한되어 있으며 전세계 브라우저의 88 %가 2017 년 7 월 현재이를 지원합니다. 다음 표는 약속을 지원하는 가장 빠른 브라우저 버전의 개요를 제공합니다.
크롬 | 가장자리 | Firefox | 인터넷 익스플로러 | 오페라 | 오페라 미니 | 원정 여행 | iOS Safari |
---|---|---|---|---|---|---|---|
32 | 12 | 27 | 엑스 | 19 | 엑스 | 7.1 | 8 |
이를 지원하지 않는 환경에서 Promise
는 폴리 폴리 될 수 있습니다. 타사 라이브러리는 콜백 함수의 자동 "약속"또는 progress
과 같은 추가 메서드 ( notify
이라고도 함)와 같은 확장 된 기능을 제공 할 수도 있습니다.
Promises / A + 표준 웹 사이트는 1.0 및 1.1 준수 구현 목록을 제공합니다. A + 표준을 기반으로 한 약속 콜백 은 이벤트 루프에서 항상 비동기 적으로 마이크로 작업으로 실행됩니다.
약속 체인
then
의 약속의 방법은 새로운 약속을 되돌려줍니다.
const promise = new Promise(resolve => setTimeout(resolve, 5000));
promise
// 5 seconds later
.then(() => 2)
// returning a value from a then callback will cause
// the new promise to resolve with this value
.then(value => { /* value === 2 */ });
돌아 오는 Promise
A로부터 then
콜백은 약속 체인에 추가합니다.
function wait(millis) {
return new Promise(resolve => setTimeout(resolve, millis));
}
const p = wait(5000).then(() => wait(4000)).then(() => wait(1000));
p.then(() => { /* 10 seconds have passed */ });
catch
방식과 유사, 거부 약속을 복구 할 수 있습니다 catch
A의 try
/ catch
문이 작동합니다. 어느 체인 then
후 catch
으로부터 해결 된 값을 사용하여 해결 핸들러를 실행 catch
.
const p = new Promise(resolve => {throw 'oh no'});
p.catch(() => 'oh yes').then(console.log.bind(console)); // outputs "oh yes"
체인 중간에 catch
핸들이나 리 reject
핸들러가없는 경우 끝에있는 catch
가 체인의 거부를 캡처합니다.
p.catch(() => Promise.reject('oh yes'))
.then(console.log.bind(console)) // won't be called
.catch(console.error.bind(console)); // outputs "oh yes"
어떤 경우에는 함수 실행을 "분기"할 수 있습니다. 조건에 따라 함수에서 다른 약속을 반환하면됩니다. 코드의 뒷부분에서 이러한 모든 분기를 하나로 병합하여 하나 이상의 다른 함수를 호출하거나 한 곳에서 모든 오류를 처리 할 수 있습니다.
promise
.then(result => {
if (result.condition) {
return handlerFn1()
.then(handlerFn2);
} else if (result.condition2) {
return handlerFn3()
.then(handlerFn4);
} else {
throw new Error("Invalid result");
}
})
.then(handlerFn5)
.catch(err => {
console.error(err);
});
따라서 함수의 실행 순서는 다음과 같습니다.
promise --> handlerFn1 -> handlerFn2 --> handlerFn5 ~~> .catch()
| ^
V |
-> handlerFn3 -> handlerFn4 -^
단일 catch
는 발생할 수있는 분기에서 오류를 가져옵니다.
소개
Promise
객체는 값을 생성했거나 결국 생성 할 연산을 나타냅니다. 약속은 비동기 작업의 결과 (대기중인 가능성이 있음)를 래핑하여 딥 중첩 콜백 ( " 콜백 지옥 "이라고 함) 문제를 완화하는 강력한 방법을 제공합니다.
상태 및 제어 흐름
약속은 세 가지 상태 중 하나에있을 수 있습니다.
- 보류 중 - 기본 작업이 아직 완료되지 않았고 약속이 보류 중 입니다.
- fulfilled - 작업이 끝났으며 약속은 가치 로 충족 됩니다. 이는 동기 함수에서 값을 반환하는 것과 유사합니다.
- 거부 - 처리 중에 에러가 발생하고, 약속을 이유로 거부됩니다. 이는 동기 함수에서 오류를 발생시키는 것과 유사합니다.
약속은 성취 또는 거부하거나 할 때 해결 (또는 해결) 할 수 있다고합니다. 약속이 일단 확정되면 불변이되고 그 상태는 바뀔 수 없습니다. 약속의 then
및 catch
메소드를 사용하면 정산 될 때 실행되는 콜백을 첨부 할 수 있습니다. 이 콜백은 각각 이행 값과 거부 이유와 함께 호출됩니다.
예
const promise = new Promise((resolve, reject) => {
// Perform some work (possibly asynchronous)
// ...
if (/* Work has successfully finished and produced "value" */) {
resolve(value);
} else {
// Something went wrong because of "reason"
// The reason is traditionally an Error object, although
// this is not required or enforced.
let reason = new Error(message);
reject(reason);
// Throwing an error also rejects the promise.
throw reason;
}
});
then
및 catch
메소드를 사용하여 이행 및 거부 콜백을 첨부 할 수 있습니다.
promise.then(value => {
// Work has completed successfully,
// promise has been fulfilled with "value"
}).catch(reason => {
// Something went wrong,
// promise has been rejected with "reason"
});
참고 : promise.then(...)
을 실행하거나 콜백 중 하나에서 오류가 발생하면 promise.then(...)
및 promise.catch(...)
를 같은 약속으로 호출하면 Uncaught exception in Promise
가 발생할 수 있습니다. 선호하는 방법은 이전에 의해 반환 된 약속을 다음 수신기를 연결하는 것입니다 then
/ catch
.
또는 두 콜백을 단일 호출로 연결하여 then
같이 할 수 있습니다.
promise.then(onFulfilled, onRejected);
이미 확정 된 약속에 콜백을 첨부하면 즉시 마이크로 탭 대기열 에 배치되고 "가능한 한 빨리"(즉, 현재 실행중인 스크립트 바로 다음에) 호출됩니다. 다른 많은 이벤트 발생 구현과 달리 콜백을 첨부하기 전에 약속의 상태를 확인할 필요는 없습니다.
지연 함수 호출
setTimeout()
메서드는 지정된 밀리 초 후에 함수를 호출하거나 표현식을 평가합니다. 또한 비동기 작업을 수행하는 간단한 방법이기도합니다.
이 예제에서 wait
함수를 호출하면 첫 번째 인수로 지정된 시간 이후에 약속이 해결됩니다.
function wait(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
wait(5000).then(() => {
console.log('5 seconds have passed...');
});
여러 동시 약속 대기 중
Promise.all()
정적 메서드는 약속의 반복 가능한 (예 : Array
)을 허용하고 반복 가능한 모든 약속이 해결 될 때 해결되는 새로운 약속을 반환하거나 반복 가능한 약속 중 하나 이상이 거부 된 경우 거부합니다.
// wait "millis" ms, then resolve with "value"
function resolve(value, milliseconds) {
return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}
// wait "millis" ms, then reject with "reason"
function reject(reason, milliseconds) {
return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
]).then(values => console.log(values)); // outputs "[1, 2, 3]" after 7 seconds.
Promise.all([
resolve(1, 5000),
reject('Error!', 6000),
resolve(2, 7000)
]).then(values => console.log(values)) // does not output anything
.catch(reason => console.log(reason)); // outputs "Error!" after 6 seconds.
iterable의 약속되지 않은 값은 "promisified" 입니다.
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
{ hello: 3 }
])
.then(values => console.log(values)); // outputs "[1, 2, { hello: 3 }]" after 6 seconds
파괴 할당은 여러 약속에서 결과를 검색하는 데 도움이 될 수 있습니다.
Promise.all([
resolve(1, 5000),
resolve(2, 6000),
resolve(3, 7000)
])
.then(([result1, result2, result3]) => {
console.log(result1);
console.log(result2);
console.log(result3);
});
여러 동시 약속 중 첫 번째 기다림
Promise.race()
정적 메서드는 약속의 반복 가능을 허용하고 반복 가능한 약속 중 첫 번째 약속이 해결되거나 거부되는 즉시 해결하거나 거부하는 새 약속을 반환합니다.
// wait "milliseconds" milliseconds, then resolve with "value"
function resolve(value, milliseconds) {
return new Promise(resolve => setTimeout(() => resolve(value), milliseconds));
}
// wait "milliseconds" milliseconds, then reject with "reason"
function reject(reason, milliseconds) {
return new Promise((_, reject) => setTimeout(() => reject(reason), milliseconds));
}
Promise.race([
resolve(1, 5000),
resolve(2, 3000),
resolve(3, 1000)
])
.then(value => console.log(value)); // outputs "3" after 1 second.
Promise.race([
reject(new Error('bad things!'), 1000),
resolve(2, 2000)
])
.then(value => console.log(value)) // does not output anything
.catch(error => console.log(error.message)); // outputs "bad things!" after 1 second
"약속"가치
Promise.resolve
정적 메서드를 사용하여 값을 약속으로 래핑 할 수 있습니다.
let resolved = Promise.resolve(2);
resolved.then(value => {
// immediately invoked
// value === 2
});
value
가 이미 약속 Promise.resolve
, Promise.resolve
단순히 그것을 재 작성합니다.
let one = new Promise(resolve => setTimeout(() => resolve(2), 1000));
let two = Promise.resolve(one);
two.then(value => {
// 1 second has passed
// value === 2
});
실제로 value
는 "thenable"(spec을 준수하는 약속처럼 충분히 작동하는 then
메소드를 정의하는 객체) 일 수 있습니다. 이를 통해 Promise.resolve
는 신뢰할 수없는 제 3 자 개체를 신뢰할 수있는 제 1 자 약속으로 변환 할 수 있습니다.
let resolved = Promise.resolve({
then(onResolved) {
onResolved(2);
}
});
resolved.then(value => {
// immediately invoked
// value === 2
});
Promise.reject
정적 메서드는 주어진 reason
와 함께 즉시 거부하는 약속을 반환합니다.
let rejected = Promise.reject("Oops!");
rejected.catch(reason => {
// immediately invoked
// reason === "Oops!"
});
콜백으로 "약속하기"기능
노드 스타일 콜백을 허용하는 함수가 주어지면,
fooFn(options, function callback(err, result) { ... });
당신은 이것을 약속 할 수 있습니다 (약속 기반 함수로 변환하십시오) :
function promiseFooFn(options) {
return new Promise((resolve, reject) =>
fooFn(options, (err, result) =>
// If there's an error, reject; otherwise resolve
err ? reject(err) : resolve(result)
)
);
}
이 함수는 다음과 같이 사용할 수 있습니다.
promiseFooFn(options).then(result => {
// success!
}).catch(err => {
// error!
});
좀 더 일반적인 방법으로 주어진 콜백 스타일 함수를 promisify하는 방법은 다음과 같습니다.
function promisify(func) {
return function(...args) {
return new Promise((resolve, reject) => {
func(...args, (err, result) => err ? reject(err) : resolve(result));
});
}
}
이것은 다음과 같이 사용할 수 있습니다 :
const fs = require('fs');
const promisedStat = promisify(fs.stat.bind(fs));
promisedStat('/foo/bar')
.then(stat => console.log('STATE', stat))
.catch(err => console.log('ERROR', err));
오류 처리
약속으로부터 던져진 오류는 then
전달 된 두 번째 매개 변수 ( reject
) 또는 catch
전달 된 핸들러에 의해 처리됩니다.
throwErrorAsync()
.then(null, error => { /* handle error here */ });
// or
throwErrorAsync()
.catch(error => { /* handle error here */ });
쇠사슬
약속 체인이 있으면 오류로 인해 resolve
핸들러가 건너 뜁니다.
throwErrorAsync()
.then(() => { /* never called */ })
.catch(error => { /* handle error here */ });
동일은 적용 then
기능. resolve
핸들러가 예외를 throw하면 다음 reject
핸들러가 호출됩니다.
doSomethingAsync()
.then(result => { throwErrorSync(); })
.then(() => { /* never called */ })
.catch(error => { /* handle error from throwErrorSync() */ });
오류 처리기는 새로운 약속을 반환하므로 약속 체인을 계속할 수 있습니다. 오류 처리기에서 반환 한 약속은 처리기에서 반환 한 값으로 확인됩니다.
throwErrorAsync()
.catch(error => { /* handle error here */; return result; })
.then(result => { /* handle result here */ });
오류를 다시 던져서 오류를 약속 체인 아래로 캐스케이드 할 수 있습니다.
throwErrorAsync()
.catch(error => {
/* handle error from throwErrorAsync() */
throw error;
})
.then(() => { /* will not be called if there's an error */ })
.catch(error => { /* will get called with the same error */ });
setTimeout
콜백 내에서 throw
문을 래핑하여 약속에 의해 처리되지 않는 예외를 throw 할 수 있습니다.
new Promise((resolve, reject) => {
setTimeout(() => { throw new Error(); });
});
이는 약속이 비동기 적으로 발생하는 예외를 처리 할 수 없기 때문에 가능합니다.
처리되지 않은 거부
약속에 catch
블록이나 reject
처리기가 없으면 오류가 자동으로 무시됩니다.
throwErrorAsync()
.then(() => { /* will not be called */ });
// error silently ignored
이를 방지하려면 항상 catch
블록을 사용하십시오.
throwErrorAsync()
.then(() => { /* will not be called */ })
.catch(error => { /* handle error*/ });
// or
throwErrorAsync()
.then(() => { /* will not be called */ }, error => { /* handle error*/ });
또는 처리되지 않은 거부 된 약속을 잡으려면 unhandledrejection
이벤트에 가입하십시오.
window.addEventListener('unhandledrejection', event => {});
어떤 약속들은 창조 시간보다 늦게 거절 할 수 있습니다. rejectionhandled
이벤트는 그러한 약속이 처리 될 때마다 시작됩니다.
window.addEventListener('unhandledrejection', event => console.log('unhandled'));
window.addEventListener('rejectionhandled', event => console.log('handled'));
var p = Promise.reject('test');
setTimeout(() => p.catch(console.log), 1000);
// Will print 'unhandled', and after one second 'test' and 'handled'
event
인수에는 거부에 대한 정보가 들어 있습니다. event.reason
은 오류 객체이고 event.promise
는 이벤트를 발생시킨 promise 객체입니다.
Nodejs에서 rejectionhandled
및 unhandledrejection
이벤트는 각각 rejectionHandled
및 unhandledRejection
process
에서 호출되며 다른 서명을가집니다.
process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});
reason
인수는 오류 오브젝트이며 promise
인수는 이벤트를 시작한 promise 오브젝트에 대한 참조입니다.
이러한 unhandledrejection
rejectionhandled
및 rejectionhandled
unhandledrejection
이벤트는 디버깅 용도로만 사용해야합니다. 일반적으로 모든 약속은 거부해야합니다.
참고 : 현재 Chrome 49 이상 및 Node.js 만 unhandledrejection
rejectionhandled
및 rejectionhandled
unhandledrejection
이벤트를 지원합니다.
주의 사항
fulfill
및 reject
와 연결
then(fulfill, reject)
함수 ( null
이 아닌 두 매개 변수 모두)는 고유하고 복잡한 동작을 가지며 정확히 작동하는 방법을 모르는 경우 사용해서는 안됩니다.
함수는 입력 중 하나에 대해 null
이 주어진 경우 예상대로 작동합니다.
// the following calls are equivalent
promise.then(fulfill, null)
promise.then(fulfill)
// the following calls are also equivalent
promise.then(null, reject)
promise.catch(reject)
그러나 두 입력이 모두 주어지면 고유 한 동작을 채택합니다.
// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.then(fulfill).catch(reject)
// the following calls are not equivalent!
promise.then(fulfill, reject)
promise.catch(reject).then(fulfill)
then(fulfill, reject)
함수는 마치 then(fulfill).catch(reject)
대한 지름길 인 것처럼 보이지만 그렇지 않다. 그러한 문제가 있다는 것입니다 reject
핸들러가에서 오류를 처리하지 않습니다 fulfill
핸들러를. 다음은 일어날 일입니다.
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }, // error in the fulfill handler
error => { /* this is not called! */ });
위의 코드는 오류가 전파되므로 약속이 거부됩니다. 이를 다음 코드와 비교하면 약속이 성취됩니다.
Promise.resolve() // previous promise is fulfilled
.then(() => { throw new Error(); }) // error in the fulfill handler
.catch(error => { /* handle error */ });
유사한 문제는 거절 된 약속 대신 성취 된 약속을 전파하는 경우를 제외하고는 then(fulfill, reject)
catch(reject).then(fulfill)
와 교환 then(fulfill, reject)
있을 때 존재합니다.
약속을 반환해야하는 함수에서 동 기적으로 던졌습니다.
다음과 같은 함수를 상상해보십시오.
function foo(arg) {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
그러한 기능이 promise chain의 중간 에서 사용된다면 분명히 아무런 문제가 없습니다.
makeSomethingAsync().
.then(() => foo('unexpectedValue'))
.catch(err => console.log(err)) // <-- Error: UnexpectedValue will be caught here
그러나 동일한 함수가 promise chain 외부에서 호출되면 오류는 해당 함수에 의해 처리되지 않고 응용 프로그램에 전달됩니다.
foo('unexpectedValue') // <-- error will be thrown, so the application will crash
.then(makeSomethingAsync) // <-- will not run
.catch(err => console.log(err)) // <-- will not catch
가능한 해결 방법에는 두 가지가 있습니다.
오류와 함께 거부 된 약속을 반환하십시오.
던지기 대신 다음과 같이하십시오.
function foo(arg) {
if (arg === 'unexepectedValue') {
return Promise.reject(new Error('UnexpectedValue'))
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
}
귀하의 기능을 약속의 사슬로 감싸십시오.
throw
문은 이미 약속 체인에있을 때 올바르게 포착됩니다.
function foo(arg) {
return Promise.resolve()
.then(() => {
if (arg === 'unexepectedValue') {
throw new Error('UnexpectedValue')
}
return new Promise(resolve =>
setTimeout(() => resolve(arg), 1000)
)
})
}
동기 및 비동기 작업 조정
경우에 따라 코드 분기에서 반복을 방지하기 위해 약속 내에 동기 작업을 래핑하려고 할 수 있습니다. 이 예제를 보자.
if (result) { // if we already have a result
processResult(result); // process it
} else {
fetchResult().then(processResult);
}
위 코드의 동기식 및 비동기식 분기는 약속 내에서 동기식 연산을 중복하여 래핑하여 조정할 수 있습니다.
var fetch = result
? Promise.resolve(result)
: fetchResult();
fetch.then(processResult);
비동기 호출의 결과를 캐싱 할 때는 결과 자체가 아닌 약속을 캐시하는 것이 바람직합니다. 이렇게하면 여러 개의 병렬 요청을 해결할 때 비동기 작업이 하나만 필요합니다.
오류 조건이 발생하면 캐시 된 값을 무효로하려면주의해야합니다.
// A resource that is not expected to change frequently
var planets = 'http://swapi.co/api/planets/';
// The cached promise, or null
var cachedPromise;
function fetchResult() {
if (!cachedPromise) {
cachedPromise = fetch(planets)
.catch(function (e) {
// Invalidate the current result to retry on the next fetch
cachedPromise = null;
// re-raise the error to propagate it to callers
throw e;
});
}
return cachedPromise;
}
배열을 묶여 약속을 줄입니다.
이 디자인 패턴은 요소 목록에서 일련의 비동기 작업을 생성하는 데 유용합니다.
두 가지 변형이 있습니다.
- 체인이 성공을 거두는 한 계속되는 체인을 만드는 "then"감소입니다.
- 체인이 오류를 경험하는 한 계속 체인을 만드는 "catch"감소.
"다음"감소
패턴의이 변형은 .then()
체인을 만들고 애니메이션 연쇄 또는 일련의 종속 HTTP 요청을 만드는 데 사용될 수 있습니다.
[1, 3, 5, 7, 9].reduce((seq, n) => {
return seq.then(() => {
console.log(n);
return new Promise(res => setTimeout(res, 1000));
});
}, Promise.resolve()).then(
() => console.log('done'),
(e) => console.log(e)
);
// will log 1, 3, 5, 7, 9, 'done' in 1s intervals
설명:
- 우리는 전화
.reduce()
소스 어레이에 제공하고Promise.resolve()
초기 값으로한다. - 감소 된 모든 요소는
.then()
을 초기 값에 추가합니다. -
reduce()
의 제품은 Promise.resolve (), then (...), then (...)이됩니다. - reduce 후에 수동으로
.then(successHandler, errorHandler)
추가하여 이전 단계가 모두 해결되면successHandler
를 실행합니다. 단계가 실패하면errorHandler
가 실행됩니다.
참고 : "then"감소는 Promise.all()
의 순차적 대응입니다.
"포획"감소
패턴의이 변형은 .catch()
체인을 만들고 작동중인 서버가 발견 될 때까지 일부 미러 된 자원에 대해 일련의 웹 서버를 순차적으로 조사하는 데 사용될 수 있습니다.
var working_resource = 5; // one of the values from the source array
[1, 3, 5, 7, 9].reduce((seq, n) => {
return seq.catch(() => {
console.log(n);
if(n === working_resource) { // 5 is working
return new Promise((resolve, reject) => setTimeout(() => resolve(n), 1000));
} else { // all other values are not working
return new Promise((resolve, reject) => setTimeout(reject, 1000));
}
});
}, Promise.reject()).then(
(n) => console.log('success at: ' + n),
() => console.log('total failure')
);
// will log 1, 3, 5, 'success at 5' at 1s intervals
설명:
- 우리는 전화
.reduce()
소스 어레이에 제공하고Promise.reject()
초기 값으로한다. - 모든 요소를 줄이면
.catch()
가 초기 값에 추가됩니다. -
reduce()
의 제품은Promise.reject().catch(...).catch(...)
됩니다. - reduce 후에 수동으로
.then(successHandler, errorHandler)
추가하여 이전 단계 중 하나가 해결되면successHandler
를 실행합니다. 모든 단계가 실패하면errorHandler
가 실행됩니다.
참고 : "catch"감소는 Promise.any()
의 순차적 대응입니다 Promise.any()
bluebird.js
구현되었지만 현재는 기본 ECMAScript에는 없습니다).
forEach와 약속
이전 요소가 처리 될 때까지 각 요소가 처리 대기 중일 때 배열의 각 요소에 약속을 반환하는 함수 ( cb
)를 효과적으로 적용 할 수 있습니다.
function promiseForEach(arr, cb) {
var i = 0;
var nextPromise = function () {
if (i >= arr.length) {
// Processing finished.
return;
}
// Process next function. Wrap in `Promise.resolve` in case
// the function does not return a promise
var newPromise = Promise.resolve(cb(arr[i], i));
i++;
// Chain to finish processing.
return newPromise.then(nextPromise);
};
// Kick off the chain.
return Promise.resolve().then(nextPromise);
};
한 번에 하나씩 수천 개의 항목을 효율적으로 처리해야하는 경우 유용 할 수 있습니다. 약속을 생성하기 위해 일반 for
루프를 사용하면 모든 것을 한 번에 생성하고 상당한 양의 RAM을 차지합니다.
finally ()를 사용하여 정리 수행
현재 약속이 성취되었는지 또는 거부되었는지에 관계없이 실행될 약속에 finally
콜백을 추가하는 제안 (ECMAScript 표준의 일부는 아님)이 있습니다. 의미 상 이것은 try
블록 의 finally
절 과 유사합니다.
일반적으로이 기능을 정리에 사용합니다.
var loadingData = true;
fetch('/data')
.then(result => processData(result.data))
.catch(error => console.error(error))
.finally(() => {
loadingData = false;
});
finally
콜백은 약속의 상태에 영향을 미치지 않습니다. 그것이 어떤 가치를 반환하는지는 중요하지 않으며, 약속은 이전에 성취 / 거부 된 상태로 머물러 있습니다. 따라서 위의 예에서 finally
콜백이 undefined
반환하더라도 약속은 processData(result.data)
의 반환 값으로 해결됩니다.
표준화 프로세스가 아직 진행 중이기 때문에 약속 구현은 finally
콜백을 기본적 finally
지원하지 않을 가능성이 높습니다. 동기 콜백의 경우 polyfill과 함께이 기능을 추가 할 수 있습니다.
if (!Promise.prototype.finally) {
Promise.prototype.finally = function(callback) {
return this.then(result => {
callback();
return result;
}, error => {
callback();
throw error;
});
};
}
비동기 API 요청
이것은 비동기 기능을 이용할 수있는 간단한 GET
API 호출의 예입니다.
var get = function(path) {
return new Promise(function(resolve, reject) {
let request = new XMLHttpRequest();
request.open('GET', path);
request.onload = resolve;
request.onerror = reject;
request.send();
});
};
다음과 같은 onload
및 onerror
함수를 사용하여보다 강력한 오류 처리를 수행 할 수 있습니다.
request.onload = function() {
if (this.status >= 200 && this.status < 300) {
if(request.response) {
// Assuming a successful call returns JSON
resolve(JSON.parse(request.response));
} else {
resolve();
} else {
reject({
'status': this.status,
'message': request.statusText
});
}
};
request.onerror = function() {
reject({
'status': this.status,
'message': request.statusText
});
};
ES2017 비동기 / 대기 사용
위의 동일한 예제 인 이미지로드 는 비동기 함수를 사용하여 작성할 수 있습니다. 또한 예외 처리를 위해 일반적인 try/catch
메서드를 사용할 수 있습니다.
참고 : 2017 년 4 월 현재 Internet Explorer를 제외한 모든 브라우저의 현재 릴리스는 비동기 기능을 지원합니다 .
function loadImage(url) {
return new Promise((resolve, reject) => {
const img = new Image();
img.addEventListener('load', () => resolve(img));
img.addEventListener('error', () => {
reject(new Error(`Failed to load ${url}`));
});
img.src = url;
});
}
(async () => {
// load /image.png and append to #image-holder, otherwise throw error
try {
let img = await loadImage('http://example.com/image.png');
document.getElementById('image-holder').appendChild(img);
}
catch (error) {
console.error(error);
}
})();