Promise 객체는 비동기 계산을 위해 사용됩니다. Promise는 아직은 아니지만 나중에 완료될 것으로 기대되는 연산을 표현합니다.

구문

new Promise( /* executor */ function(resolve, reject) { ... } );

매개변수

executor
resolvereject 인수를 통해 다른 함수에 전달될 함수입니다. executor 함수는 resolvereject 함수를 제공하는 promise 구현에 의해 즉시 실행됩니다. (executor는 Promise 생성자가 객체를 반환하기도 전에 호출됩니다.) resolvereject 함수는 프로미스에 바인딩되고 둘을 호출하면 각각 프로미스를 이행(fulfill) 또는 거부(reject, 거절)합니다. executor는 일부 비동기 작업(work)을 시작하리라 예상되고 작업이 완료되면 프로미스의 최종값을 결정(resolve, 확정)하거나 오류가 발생하면 거부하기 위해 resolve 또는 reject 함수를 호출합니다.

설명

Promise는 프로미스가 생성될 때 꼭 알 필요는 없는 값을 위한 대리자입니다. 이는 비동기 동작이 종료된 이후의 결과값이나 실패 이유를 처리하기 위한 처리기(handler)를 연결할 수 있도록 합니다. 프로미스는 비동기 메서드가 동기 메서드처럼 값을 반환하도록 합니다. 최종값 대신, 비동기 메서드는 미래 어느 시점에 값을 갖는 promise를 반환합니다.

Promise는 다음 중 하나의상태를 가집니다.

  • 대기중(pending): 초기 상태, 이행 또는 거부되지 않은.
  • 이행됨(fulfilled): 연산이 성공리에 완료되었음을 뜻합니다.
  • 거부됨(rejected): 연산이 실패했음을 뜻합니다.

대기중인 프로미스는 값으로 이행되거나, 이유(reason 또는 오류)와 함께 거부될 수 있습니다. 이 중 하나가 일어난 경우, 연결된 처리기는 호출된 프로미스의 then 메서드에 의해 대기열에 오릅니다(queued up). (프로미스에 처리기가 부착될 때 이미 이행 또는 거부된 경우에도 처리기는 호출되므로, 비동기 연산과 부착될 처리기 사이에는 경합 조건(race condition)이 없습니다.)

Promise.prototype.then()Promise.prototype.catch() 메서드가 프로미스를 반환하기에, 둘은 연결(chain)될 수 있습니다—합성(composition)이라고 불립니다.

혼동하지 않도록 하세요: 여러 다른 언어(가령 Scheme)에는 게으른(lazy) 평가 및 계산을 연기하기 위한 메커니즘이 있는데 그들도 “promise”라고 부릅니다. JavaScript에서 프로미스는 이미 생긴 프로세스를 나타내고, 이는 콜백 함수로 연결(chain)될 수 있습니다. 당신이 식(expression)을 게으르게 평가할 길을 찾고 있는 경우, 게으르게 평가되는 식을 만들기 위한 인수 없는 화살표 함수: f = () => expression 와 평가하는 f()를 고려하세요.

주의: 프로미스는 대기중이 아니라 이행 또는 거부된 경우 처리되었다(settled)고 합니다. 또한 프로미스와 함께 쓰이는 용어 (운명이) 결정됨(resolved)도 듣기 마련입니다 — 이는 프로미스가 (상태가) 처리됨(settled) 또는 프로미스 (처리) 체인 내에 갖힘(locked)을 뜻합니다. 프로미스 용어에 관한 더 자세한 사항은 Domenic Denicola의 글 상태와 운명에 담겨 있습니다.

속성

Promise.length
값이 언제나 1인 Length 속성입니다. (생성자 인수의 수를 나타냅니다.)
Promise.prototype
Promise 생성자의 프로토타입을 나타냅니다.

메서드

Promise.all(iterable)
인수 iterable 내의 모든 프로미스가 결정된 때 결정되며 하나의 프로미스라도 거부된 경우 즉시 거부하는 프로미스를 반환합니다. 이 프로미스가 결정되는 경우, iterable 내의 프로미스가 결정한 값들의 배열로 결정됩니다. 반환된 프로미스가 거부되는 경우, iterable 내의 거부된 그 프로미스가 거부된 이유를 그대로 이용해 거부합니다. 이 메서드는 여러 프로미스의 결과를 모두 모으는 데 유용할 수 있습니다.
Promise.race(iterable)
iterable 내 프로미스 중 하나를 결정 또는 거부하자마자 결정 또는 거부하는 프로미스를 반환합니다, 그 프로미스로부터 값 또는 이유로.
Promise.reject(reason)
주어진 reason(이유)로 거부된 Promise 객체를 반환합니다.
Promise.resolve(value)
주어진 값(value)으로 결정된 Promise 객체를 반환합니다. 값이 thenable 객체인(즉 then 메서드가 있는) 경우, 반환된 프로미스는 그 thenable을 "따르고(follow)", 그 최종 상태를 취합니다; 그렇지 않으면 반환된 프로미스는 그 값으로 이행됩니다. 보통, 값이 프로미스인지 아닌지 알고 싶은 경우 - 대신 Promise.resolve(value)로 쓰고 프로미스처럼 반환값으로 작동합니다.

Promise 프로토타입

속성

Promise.prototype.constructor
인스턴스의 프로토타입을 만드는 함수를 반환합니다. 이는 기본으로 Promise 함수입니다.

메서드

Promise.prototype.catch(onRejected)
프로미스(promise)에 거부 처리기 콜백을 추가하고 호출된 경우 콜백의 반환값 또는 프로미스가 대신 이행된 경우 그 원래 이행(fulfillment)값으로 결정하는(resolving) 새 프로미스를 반환합니다.
Promise.prototype.then(onFulfilled, onRejected)
프로미스에 이행 또는 거부 처리기를 추가하고 호출된 처리기의 반환값 또는 프로미스가 처리되지 않은 경우 그 원래 처리된(settled) 값으로 결정하는 새 프로미스를 반환합니다 (즉 관련 처리기 onFulfilled 또는 onRejectedundefined인 경우).

Promise 생성

이 간단한 예는 Promise의 메커니즘을 보입니다. testPromise() 메서드는 <button>이 클릭될 때마다 호출됩니다. 결정하는 프로미스를 만듭니다, 무작위로 1-3초마다 프로미스 셈(1부터 시작하는 숫자)에 window.setTimeout()을 사용하는. Promise() 생성자는 프로미스를 만드는 데 쓰입니다.

프로미스 이행은 간단하게 기록(log)됩니다, p1.then()을 사용하는 이행 콜백 세트를 통해. 기록 약간이 메서드의 동기 부분을 프로미스의 비동기 완료(completion)와 분리(decouple)되는 법을 보입니다.

'use strict';
var promiseCount = 0;

function testPromise() {
    var thisPromiseCount = ++promiseCount;

    var log = document.getElementById('log');
    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Started (<small>Sync code started</small>)<br/>');

    // 새 약속을 (생성)합니다: 이 프로미스의 숫자 셈을 약속합니다, 1부터 시작하는(3s 기다린 뒤)
    var p1 = new Promise(
        // resolver(결정자) 함수는 프로미스 (이행을) 결정 또는 거부하는
        // 능력과 함께 호출됩니다
        function(resolve, reject) {
            log.insertAdjacentHTML('beforeend', thisPromiseCount +
                ') Promise started (<small>Async code started</small>)<br/>');
            // 이는 비동기를 만드는 예에 불과합니다
            window.setTimeout(
                function() {
                    // 프로미스 이행 !
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        }
    );

    // 프로미스가 then() 호출로 결정된/이행된 경우 무엇을 할 지를 정의하고,
    // catch() 메서드는 프로미스가 거부된 경우 무엇을 할 지를 정의합니다.
    p1.then(
        // 이행값 기록
        function(val) {
            log.insertAdjacentHTML('beforeend', val +
                ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
        })
    .catch(
        // 거부 이유 기록
        function(reason) {
            console.log('Handle rejected promise ('+reason+') here.');
        });

    log.insertAdjacentHTML('beforeend', thisPromiseCount +
        ') Promise made (<small>Sync code terminated</small>)<br/>');
}

이 예는 버튼을 클릭하면 실행됩니다. Promise를 지원하는 브라우저가 필요합니다. 짧은 시간 안에 버튼을 여러 번 클릭하여, 서로 다른 프로미스가 번갈아 이행되는 것을 볼 수도 있습니다.

new XMLHttpRequest()를 쓰는 예

Promise 생성 2

이 예는 XMLHttpRequest의 성공 또는 실패를 보고하기 위해 Promise를 사용하는 메서드의 구현을 보입니다.

'use strict';

// A-> $http 함수는 표준 Adapter 패턴을 따르기 위해 구현됩니다
function $http(url){

  // 간단한 사례 객체
  var core = {

    // ajax 요청을 수행하는 메서드
    ajax: function (method, url, args) {

      // 프로미스 생성
      var promise = new Promise( function (resolve, reject) {

        // XMLHttpRequest 인스턴스화
        var client = new XMLHttpRequest();
        var uri = url;

        if (args && (method === 'POST' || method === 'PUT')) {
          uri += '?';
          var argcount = 0;
          for (var key in args) {
            if (args.hasOwnProperty(key)) {
              if (argcount++) {
                uri += '&';
              }
              uri += encodeURIComponent(key) + '=' + encodeURIComponent(args[key]);
            }
          }
        }

        client.open(method, uri);
        client.send();

        client.onload = function () {
          if (this.status >= 200 && this.status < 300) {
            // this.status가 2xx와 같은 경우 함수 "resolve" 수행
            resolve(this.response);
          } else {
            // this.status가 2xx와 다른 경우 함수 "reject" 수행
            reject(this.statusText);
          }
        };
        client.onerror = function () {
          reject(this.statusText);
        };
      });

      // 프로미스 반환
      return promise;
    }
  };

  // Adapter 패턴
  return {
    'get': function(args) {
      return core.ajax('GET', url, args);
    },
    'post': function(args) {
      return core.ajax('POST', url, args);
    },
    'put': function(args) {
      return core.ajax('PUT', url, args);
    },
    'delete': function(args) {
      return core.ajax('DELETE', url, args);
    }
  };
};
// A의 끝

// B-> 여기서 그 함수 및 payload를 정의합니다
var mdnAPI = 'https://developer.mozilla.org/en-US/search.json';
var payload = {
  'topic' : 'js',
  'q'     : 'Promise'
};

var callback = {
  success: function(data) {
    console.log(1, 'success', JSON.parse(data));
  },
  error: function(data) {
    console.log(2, 'error', JSON.parse(data));
  }
};
// B의 끝

// 메서드 호출 실행
$http(mdnAPI)
  .get(payload)
  .then(callback.success)
  .catch(callback.error);

// 메서드 호출을 실행하지만 프로미스 거부 경우를 다루는 다른 방법 (1)
$http(mdnAPI)
  .get(payload)
  .then(callback.success, callback.error);

// 메서드 호출을 실행하지만 프로미스 거부 경우를 다루는 다른 방법 (2)
$http(mdnAPI)
  .get(payload)
  .then(callback.success)
  .then(undefined, callback.error);

XHR로 이미지 로딩

이미지를 로드하기 위해 PromiseXMLHttpRequest를 사용하는 또 다른 간단한 예는 MDN GitHub promise-test 저장소에서 이용할 수 있습니다. 실제 예를 볼 수도 있습니다. 각 단계는 주석이 되어 있어 프로미스 및 XHR 구조를 철저히 따를 수 있습니다.

스펙

스펙 상태 설명
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Promise' in that specification.
Standard ECMA 표준에서 초기 정의.
ECMAScript Latest Draft (ECMA-262)
The definition of 'Promise' in that specification.
Living Standard  

브라우저 호환성

Feature Chrome Edge Firefox (Gecko) Internet Explorer Opera Safari
Basic support 32.0 (Yes) 29.0 (29.0) No support 19 7.1
Feature Android Android Webview Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile Chrome for Android
Basic support No support (Yes) 29.0 (29.0) No support No support 8 32.0

참조

문서 태그 및 공헌자

 이 페이지의 공헌자: NessunKim, ahnjungho, Netaras, redcamel, EunwooCho, akic4op4, 0xABCDEF
 최종 변경: NessunKim,