Promise 物件代表一個將完成(或失敗)的一個非同步操作,所產生的值。

此條目為介紹 Promise 建構式。要瞭解 Promise 相關使用方式,請先參考使用 Promise。Promise 建構式主要用於包裹尚未支援 Promise 的函式。

語法

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

參數

executor
為一個函式,依序接收兩個參數 resolve 及 reject(實現及拒絕回呼函式)。於 Promise 的實作中,executor 函式在傳入參數 resolve 與 reject 後立刻被執行(executor 函式會在 Promise 建構式回傳 Promise 物件前被執行)。當呼叫 resolve 或 reject 回呼函式時,分別地實現或拒絕 promise。通常 executor 函式用來發起一些非同步操作,完成後,擇一呼叫回呼函式實現(resolve)或,若有錯誤發生,拒絕(reject)promise。
如果有錯誤在 executor 函式執行過程中被拋出,promise 被拒絕(rejected),回傳值將被忽略。

描述

Promise 代理一個當它被建立時可以不知道的值。它使你能夠繫結(associate)處理函示(handlers)與一個非同步操作最終的成功值(success value)或失敗訊息(failure reason)。這讓非同步方法回傳值的方式很像同步方法,但是並非回傳最終結果:非同步方法回傳一個 promise 物件作為未來某個時間點的值。

一個 Promise 物件處於以下幾種狀態:

  • 擱置(pending):初始狀態,不是 fulfilled 與 rejected。
  • 實現(fulfilled):表示操作成功地完成。
  • 拒絕(rejected):表示操作失敗了。

一個處於擱置狀態的 promise 能以一個值被實現(fulfilled),或是以一個原因或錯誤而被拒絕(rejected)。當上述任一狀態轉換發生時,那些透過 then 方法所繫結(associated)的處理函式列隊就會依序被調用。(若一個 promise 已被實現或拒絕,繫結(attached)於它的處理函式將立即被呼叫,因此完成非同步操作與繫結處理函式之間不存在競爭條件(race condition)。)

由於 Promise.prototype.then() 以及 Promise.prototype.catch() 方法都回傳 promise,它們可以被串接。

容易混淆: 許多其他語言擁有機制用來惰性求值(lazy evaluation)及延遲(deferring)運算,它們也被稱作“promises” — e.g. Scheme. 然而在 JavaScript 中 Promises 代表那些(已經)發生中(happening)的程序,它們可以繫結回呼函式。若您要找的是惰性求值表示式,考慮不帶參數的 arrow functionf = () => expression 來建立惰性求值表示式,並透過 f() 進行求值.

Note: 一個被實現或拒絕,但不處於 pending 的 promise 被稱作被解決(settled)。您也會見到使用解決(resolved)一詞來描述 promises — 這代表 promises 被實現(fulfilled)了。States and fates 這篇文章包含了更多 promises 的專有名詞。

屬性

Promise.length
長度屬性,值固定為 1。(建構式參數數目).
Promise.prototype
Promise 建構式的原型(prototype).

方法

Promise.all(iterable)
回傳一個 promise,當在引數 iterable 中所有 promises 都被實現時被實現,或在引數 iterable 中有一個 promise 被拒絕時立刻被拒絕。若回傳的 promise 被實現,它將以一個實現值的陣列被實現,其順序與 iterable 中的 promises 相同。若回傳的 promise 被拒絕,它將以失敗訊息被拒絕,此訊息來自第一個在 iterable 中被拒絕的 promise。這個方法在聚集許多 promises 的結果時很有效。
Promise.race(iterable)
回傳一個被實現或拒絕的 promise,當 iterable 中有一個 promise 被實現或拒絕時。
Promise.reject(reason)
回傳一個以失敗訊息拒絕的 promise
Promise.resolve(value)
回傳一個以 value 實現的 promise。若該值為 thenable (i.e. 具有 then 方法),回傳的 promise 將跟隨(follow)之,採用她的最終狀態; 在其他情形回傳的 promise 將以 value 被實現。一般來說,當您不知道 value 是否為 promise,使用 Promise.resolve(value),將回傳值以 promise 作處理。

Promise 原型

屬性

Promise.prototype.constructor
回傳一個建立實例原型(instance's prototype)的函式。預設為 Promise 函數。

方法

Promise.prototype.catch(onRejected)
繫結一個拒絕回呼函式(rejection handler callback)到 promise,當它被呼叫時回傳一個以回傳值作解析的新 promise,或者當 promise 被實現時以原值作解析。
Promise.prototype.then(onFulfilled, onRejected)
繫結實現或拒絕回呼函式到 promise,回傳一個以 handler 之回傳值作解析的新 promise,或者當 promise 未處理(not handled)時以原值作解析。(i.e. 比如相關聯的 onFulfilled 或 onRejected 不是函式。)

建立 Promise

一個 Promise 物件透過 new 及其建構式建立。這個建構式接收一個叫作”執行器函式(executor function)“的引數。此函式接收兩個函式作為引數。第一個函式(resolve)在非同步作業成功完成時,以該作業之結果值被呼叫。第二個函式(reject)在作業失敗時,以失敗訊息,通常是一個 error object,被呼叫。

const myFirstPromise = new Promise((resolve, reject) => {
  // 執行一些非同步作業,最終呼叫:
  //
  //   resolve(someValue); // 實現
  // 或
  //   reject("failure reason"); // 拒絕
});

要提供一個函式 promise 功能,讓它回傳一個 promise 即可:

function myAsyncFunction(url) {
  return new Promise((resolve, reject) => {
    const xhr = new XMLHttpRequest();
    xhr.open("GET", url);
    xhr.onload = () => resolve(xhr.responseText);
    xhr.onerror = () => reject(xhr.statusText);
    xhr.send();
  });
};

範例

入門範例

let myFirstPromise = new Promise((resolve, reject) => {
  // 當非同步作業成功時,呼叫 resolve(...),而失敗時則呼叫 reject(...)。
  // 在這個例子中,使用 setTimeout(...) 來模擬非同步程式碼。
  // 在實務中,您將可能使用像是 XHR 或者一個 HTML5 API.
  setTimeout(function(){
    resolve("Success!"); // Yay!非常順利!
  }, 250);
});

myFirstPromise.then((successMessage) => {
  // successMessage 是任何您由上方 resolve(...) 傳入的東西。
  // 在此僅作為成功訊息,但是它不一定是字串。
  console.log("Yay! " + successMessage);
});

進階範例

這個小範例演示了 Promise 的運作機制。每當 <button> 被點擊時,testPromise() 方法被呼叫。每次點擊將透過 window.setTimeout() 建立一個將在 1-3 秒內隨機地被實現的 promise,供 promise 計數(一個從 1 開始的數值)。建構式 Promise() 被用來建立 promise。

promise 的實現值單純地經由一個實現回呼函式 p1.then() 被印出。下以一些文字紀錄來展現方法中同步的與非同步處理 promise 的部分是如何分離彼此。

'use strict';
var promiseCount = 0;

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

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

    // 建立一個新的 promise:此 promise 承諾一個數值計數, 由 1 開始(等待約 2 秒)
    let p1 = new Promise(
        // 這個解決器函數(resolver function)呼叫實現或
        // 拒絕 promise。
        (resolve, reject) => {
            log.insertAdjacentHTML('beforeend', thisPromiseCount +
                ') Promise started (<small>Async code started</small>)<br/>');
            // 在此例子單純用來產生非同步特性。
            window.setTimeout(
                function() {
                    // 實現這個 promise!
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        }
    );

    // 接著透過呼叫 then() 來決定 promise 進入 resolved/rejected 時要做什麼,
    // 或是 catch() 方法來決定進入 rejected 要做什麼。
    p1.then(
        // 印出實現值(fulfillment value)
        function(val) {
            log.insertAdjacentHTML('beforeend', val +
                ') Promise fulfilled (<small>Async code terminated</small>)<br/>');
        })
    .catch(
        // 印出失敗訊息(rejection reason)
        (reason) => {
            console.log('Handle rejected promise ('+reason+') here.');
        });

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

*譯註:resolver function 即 executor function。

這個範例從點擊按鈕開始。您的瀏覽器需要支援 Promise。在短時間內點擊按鈕許多次,您甚至將看到不同的 promises 一個接一個地被實現。

使用 XHR 載入圖片

另一個使用 Promise 與 XMLHttpRequest 來載入圖片的簡單例子可以在 MDN GitHub js-examples 儲存庫找到。您也可以 see it in action。每個步驟都附以註解讓您能夠一步一步跟隨 Promise 與 XHR 架構。

規範

Specification Status Comment
ECMAScript 2015 (6th Edition, ECMA-262)
The definition of 'Promise' in that specification.
Standard Initial definition in an ECMA standard.
ECMAScript Latest Draft (ECMA-262)
The definition of 'Promise' in that specification.
Living Standard  

瀏覽器相容性

FeatureChromeEdgeFirefoxInternet ExplorerOperaSafari
Basic support32 Yes291 No1983
FeatureAndroid webviewChrome for AndroidEdge mobileFirefox for AndroidIE mobileOpera AndroidiOS Safari
Basic support4.4.432 Yes291 No Yes83

1. Constructor requires a new operator since version 37.

2. Constructor requires a new operator since version 4.

3. Constructor requires a new operator since version 10.

參見

文件標籤與貢獻者

 此頁面的貢獻者: nyngwang, jackblackevo
 最近更新: nyngwang,