非常教程

JavaScript参考手册

Promise

promise.then

then()方法返回一个  Promise。它最多需要有两个参数:Promise 的成功和失败情况的回调函数。

如果忽略针对某个状态的回调函数参数,或者提供非函数 (nonfunction) 参数,那么 then 方法将会丢失关于该状态的回调函数信息,但是并不会产生错误。如果调用 thenPromise 的状态(fulfillment 或 rejection)发生改变,但是 then 中并没有关于这种状态的回调函数,那么 then 将创建一个没有经过回调函数处理的新 Promise 对象,这个新 Promise 只是简单地接受调用这个 then的原 Promise 的终态作为它的终态。

语法

p.then(onFulfilled[, onRejected]);

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

参数

onFulfilled当Promise变成接受状态(fulfillment)时,该参数作为回调函数被调用(参考: Function)。该函数有一个参数,即接受的值(the fulfillment  value)。onRejected当Promise变成拒绝状态(rejection )时,该参数作为回调函数被调用(参考: Function)。该函数有一个参数,,即拒绝的原因(the rejection reason)

返回值

then方法返回一个Promise,而它的行为与then中的回调函数的返回值有关:

  • 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。

  • 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。

  • 如果then中的回调函数返回一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。

  • 如果then中的回调函数返回一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。

  • 如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。

以下举例说明该then方法的异步性。

// using a resolved promise, the 'then' block will be triggered instantly, but its handlers will be triggered asynchronously as demonstrated by the console.logs
var resolvedProm = Promise.resolve(33);

var thenProm = resolvedProm.then(function(value){
    console.log("this gets called after the end of the main stack. the value received and returned is: " + value);
    return value;
});
// instantly logging the value of thenProm
console.log(thenProm);

// using setTimeout we can postpone the execution of a function to the moment the stack is empty
setTimeout(function(){
    console.log(thenProm);
});


// logs, in order:
// Promise {[[PromiseStatus]]: "pending", [[PromiseValue]]: undefined}
// "this gets called after the end of the main stack. the value received and returned is: 33"
// Promise {[[PromiseStatus]]: "resolved", [[PromiseValue]]: 33}

描述

由于 then 和 Promise.prototype.catch()方法都会返回 promise,它们可以被链式调用 — 一种称为复合( 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 对象,其允许方法链。

你可以传递一个 lambda 给 then 并且如果它返回一个 promise,一个等价的 Promise 将暴露给后续的方法链。下面的代码片段使用 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 returning 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 the string is actually processed by the mocked asynchronous code in the
  // previous 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);
  });

当一个值只是从一个then内部返回时,它将有效地返回 Promise.resolve(<由被调用的处理程序返回的值>)。

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.resolve()
  .then( () => {
    // Makes .then() return a rejected promise
    throw 'Oh no!';
  })
  .then( () => { 
    console.log( 'Not called.' );
  }, reason => {
    console.error( 'onRejected function called: ', reason );
  });

在其他情况下,一个 resolving Promise 会被返回。在下面的例子里,第一个 then() 会返回一个用 resolving Promise 包装的 42,即使之前的 Promise 是 rejected 的。

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

实际上,捕获 rejected 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的返回值就会被 Promise resolved或者rejected。

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

浏览器兼容性

Feature

Chrome

Edge

Firefox

Internet Explorer

Opera

Safari

Basic Support

32.0

(Yes)

29.0

No

19

7.1

Feature

Android

Chrome for Android

Edge mobile

Firefox for Android

IE mobile

Opera Android

iOS Safari

Basic Support

4.4.4

32.0

(Yes)

29

No

(Yes)

8.0

JavaScript

JavaScript 是一种高级编程语言,通过解释执行,是一门动态类型,面向对象(基于原型)的解释型语言。它已经由ECMA(欧洲电脑制造商协会)通过 ECMAScript 实现语言的标准化。它被世界上的绝大多数网站所使用,也被世界主流浏览器( Chrome、IE、FireFox、Safari、Opera )支持。JavaScript 是一门基于原型、函数先行的语言,是一门多范式的语言,它支持面向对象编程,命令式编程,以及函数式编程。它提供语法来操控文本、数组、日期以及正则表达式等,不支持 I/O,比如网络