수색…


통사론

  • 새로운 약속 (/ * 실행자 함수 : * / 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 문이 작동합니다. 어느 체인 thencatch 으로부터 해결 된 값을 사용하여 해결 핸들러를 실행 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 - 작업이 끝났으며 약속은 가치충족 됩니다. 이는 동기 함수에서 값을 반환하는 것과 유사합니다.
  • 거부 - 처리 중에 에러가 발생하고, 약속을 이유로 거부됩니다. 이는 동기 함수에서 오류를 발생시키는 것과 유사합니다.

약속은 성취 또는 거부하거나 할 때 해결 (또는 해결) 할 수 있다고합니다. 약속이 일단 확정되면 불변이되고 그 상태는 바뀔 수 없습니다. 약속의 thencatch 메소드를 사용하면 정산 될 때 실행되는 콜백을 첨부 할 수 있습니다. 이 콜백은 각각 이행 값과 거부 이유와 함께 호출됩니다.

약속의 흐름도

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;
    }
});

thencatch 메소드를 사용하여 이행 및 거부 콜백을 첨부 할 수 있습니다.

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에서 rejectionhandledunhandledrejection 이벤트는 각각 rejectionHandledunhandledRejection process 에서 호출되며 다른 서명을가집니다.

process.on('rejectionHandled', (reason, promise) => {});
process.on('unhandledRejection', (reason, promise) => {});

reason 인수는 오류 오브젝트이며 promise 인수는 이벤트를 시작한 promise 오브젝트에 대한 참조입니다.

이러한 unhandledrejection rejectionhandledrejectionhandled unhandledrejection 이벤트는 디버깅 용도로만 사용해야합니다. 일반적으로 모든 약속은 거부해야합니다.

참고 : 현재 Chrome 49 이상 및 Node.js 만 unhandledrejection rejectionhandledrejectionhandled unhandledrejection 이벤트를 지원합니다.

주의 사항

fulfillreject 와 연결

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

설명:

  1. 우리는 전화 .reduce() 소스 어레이에 제공하고 Promise.resolve() 초기 값으로한다.
  2. 감소 된 모든 요소는 .then() 을 초기 값에 추가합니다.
  3. reduce() 의 제품은 Promise.resolve (), then (...), then (...)이됩니다.
  4. 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

설명:

  1. 우리는 전화 .reduce() 소스 어레이에 제공하고 Promise.reject() 초기 값으로한다.
  2. 모든 요소를 ​​줄이면 .catch() 가 초기 값에 추가됩니다.
  3. reduce() 의 제품은 Promise.reject().catch(...).catch(...) 됩니다.
  4. 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();
  });
};

다음과 같은 onloadonerror 함수를 사용하여보다 강력한 오류 처리를 수행 할 수 있습니다.

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);
    }

})();


Modified text is an extract of the original Stack Overflow Documentation
아래 라이선스 CC BY-SA 3.0
와 제휴하지 않음 Stack Overflow