MDN wants to learn about developers like you: https://qsurvey.mozilla.com/s3/MDN-dev-survey

then() 方法回傳一個 Promise。它接收兩個引數:Promise 在成功及失敗時的回調函數。

如果參數有一個或兩個都被省略,或是以非函數(non-functions)提供,則 then 將處於遺失 handler(s) 的狀態,但不會產生任何錯誤。當 Promise 採取了任一個狀態(fulfillment 或 rejection)而 then 沒有對應的 handler,則一個新的不具有額外 handlers 的 Promise 物件將被建立,並單純採用呼叫 then 的 Promise 其最終狀態。

語法

p.then(onFulfilled[, onRejected]);

p.then(function(value) {
  // fulfillment
}, function(reason) {
  // rejection
});

*譯注:依據Note,應該是 p.then([onFulfilled[, onRejected]]); 才對,這裡選擇保留原文,有發現的朋友可以不必在意 :)

參數

onFulfilled
任一 Function,當 Promise 被實現(fulfilled)時被呼叫。此函數接收一個引數,叫實現值(fullfillment value)。
onRejected 選擇性
任一 Function,當 Promise 被否決(rejected)時被呼叫。此函數接收一個引數,叫否決因子(rejection reason)。

回傳值

一個進入擱置(pending)狀態的 Promise。(只要堆疊一空)handler 函數接著被非同步地(asynchronously)呼叫。在調用 handler 後,若 handler 函數:

  • 回傳一個值,則 then 回傳之 promise 被實現(resolved)並以之作為它的值。
  • 拋出一個例外,則 then 回傳之 promise 被否決(rejected)並以之作為它的值。
  • 回傳一個被實現的 promise,則 then 回傳之 promise 以其值被實現。
  • 回傳一個被否決的 promise,則 then 回傳之 promise 以其值被否決。
  • 回傳另一個被擱置的 promise 物件,則 then 回傳之 promise 之實現/否決將隨後由 handler 之實現/否決決定。並且,該引數值將與其值相同。

以下例子展示 then 方法的非同步性質(asynchronicity)。

// 使用一個已實現的 promise,'then' 區塊將立即被觸發,但是它的 handlers 將是非同步地被觸發,如同 console.logs 所示
var resolvedProm = Promise.resolve(33);

var thenProm = resolvedProm.then(function(value){
    console.log("我在 main stack 之後被呼叫。收到及將回傳的值為:" + value);
    return value;
});
// 立即紀錄 thenProm
console.log(thenProm);

// 我們可以使用 setTimeout 以延遲(postpone)函數執行直到堆疊為空
setTimeout(function(){
    console.log(thenProm);
});


// 紀錄結果,依序為:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "我在 main stack 之後被呼叫。收到及將回傳的值為:33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}

描述

因為 then 和 Promise.prototype.catch() 方法都回傳 promises,它們可以被串接 — 這稱作組合(composition)。

範例

運用 then 方法

var p1 = new Promise( (resolve, reject) => {
  resolve('Success!');
  // or
  // reject ("Error!");
} );

p1.then( value => {
  console.log(value); // Success!
}, reason => {
  console.log(reason); // Error!
} );

串接

 then 方法回傳一個 Promise 而可以進行方法串接(method chaining)。

如果傳入 then 的 handler 函數回傳的是一個 promise,一個等價的 Promise 將被展現給方法串接中的下一個 then 。以下程式碼片段透過 setTimout 函數進行非同步程式碼模擬。

Promise.resolve('foo')
  // 1. Receive "foo" concatenate "bar" to it and resolve that to the next then
  .then(function(string) {
    return new Promise(function(resolve, reject) {
      setTimeout(function() {
        string += 'bar';
        resolve(string);
      }, 1);
    });
  })
  // 2. receive "foobar", register a callback function to work on that string
  // and print it to the console, but not before return the unworked on
  // string to the next then
  .then(function(string) {
    setTimeout(function() {
      string += 'baz';
      console.log(string);
    }, 1)
    return string;
  })
  // 3. print helpful messages about how the code in this section will be run
  // before string is actually processed by the mocked asynchronous code in the
  // prior then block.  
  .then(function(string) {
    console.log("Last Then:  oops... didn't bother to instantiate and return " +
                "a promise in the prior then so the sequence may be a bit " +
                "surprising");

    // Note that `string` will not have the 'baz' bit of it at this point. This 
    // is because we mocked that to happen asynchronously with a setTimeout function
    console.log(string);
  });

當 handler 僅回傳一個值,實際上它將回傳 Promise.resolve(<value returned by whichever handler was called>).

var p2 = new Promise(function(resolve, reject) {
  resolve(1);
});

p2.then(function(value) {
  console.log(value); // 1
  return value + 1;
}).then(function(value) {
  console.log(value + '- This synchronous usage is virtually pointless'); // 2- This synchronous usage is virtually pointless
});

p2.then(function(value) {
  console.log(value); // 1
});

若函數拋出一個錯誤或回傳一個被否決的 Promise,then 也將回傳一個被否決的 Promise。

Promise.resolve()
  .then( () => {
    // 使 .then() 回傳一個被否決的 Promise
    throw 'Oh no!';
  })
  .then( () => { 
    console.log( 'Not called.' );
  }, reason => {
    console.error( 'onRejected function called: ', reason );
  });

任何其他情況,解析中的 Promise 被回傳。在以下例子中,第一個 then() 將回傳一個解析中納 42 的 Promise,即使串接中的前一個 Promise 被否決。

Promise.reject()
  .then( () => 99, () => 42 ) // onRejected returns 42 which is wrapped in a resolving Promise
  .then( solution => console.log( 'Resolved with ' + solution ) ); // Resolved with 42

實務上,捕捉(catch)被否決的 Promise 總是較理想的,較不偏向使用 then 的雙引數語法,如下展示。

Promise.resolve()
  .then( () => {
    // Makes .then() return a rejected promise
    throw 'Oh no!';
  })
  .catch( reason => {
    console.error( 'onRejected function called: ', reason );
  })
  .then( () => {
    console.log( "I am always called even if the prior then's promise rejects" );
  });


你也可以透過串接實作一個 Promise-based API 函數,基於它本身。

function fetch_current_data() {
  // The fetch() API returns a Promise.  This function
  // exposes a similar API, except the fulfillment
  // value of this function's Promise has had more
  // work done on it.
  return fetch('current-data.json').then((response) => {
    if (response.headers.get('content-type') != 'application/json') {
      throw new TypeError();
    }
    var j = response.json();
    // maybe do something with j
    return j; // fulfillment value given to user of
              // fetch_current_data().then()
  });
}

若 onFulfilled 回傳一個 promise,則 then 的實現/否決將取決它。

function resolveLater(resolve, reject) {
  setTimeout(function () {
    resolve(10);
  }, 1000);
}
function rejectLater(resolve, reject) {
  setTimeout(function () {
    reject(20);
  }, 1000);
}

var p1 = Promise.resolve('foo');
var p2 = p1.then(function() {
  // Return promise here, that will be resolved to 10 after 1 second
  return new Promise(resolveLater);
});
p2.then(function(v) {
  console.log('resolved', v);  // "resolved", 10
}, function(e) {
  // not called
  console.log('rejected', e);
});

var p3 = p1.then(function() {
  // Return promise here, that will be rejected with 20 after 1 second
  return new Promise(rejectLater);
});
p3.then(function(v) {
  // not called
  console.log('resolved', v);
}, function(e) {
  console.log('rejected', e); // "rejected", 20
});

規範

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

瀏覽器相容性

No compatibility data found. Please contribute data for "javascript/promise" to the MDN compatibility data repository.

參見

文件標籤與貢獻者

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