阿西河

所有教程

公众号
🌙
阿西河前端的公众号

我的收藏

    最近访问  (文章)

      教程列表

      抓包专区
      测试专区

      JS promise then()

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

      The source for this interactive demo is stored in a GitHub repository. If you’d like to contribute to the interactive demo project, please clone https://github.com/mdn/interactive-examples and send us a pull request.

      注意:如果忽略针对某个状态的回调函数参数,或者提供非函数 (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)。如果传入的 onFulfilled 参数类型不是函数,则会在内部被替换为(x) => x ,即原样返回 promise 最终结果的函数

      onRejected

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

      var p = new Promise((resolve, reject) => {
          resolve('foo')
      })
      
      // 'bar' 不是函数,会在内部被替换为 (x) => x
      p.then('bar').then((value) => {
          console.log(value) // 'foo'
      })
      

      返回值

      当一个Promise完成(fulfilled)或者失败(rejected),返回函数将被异步调用(由当前的线程循环来调度完成)。具体的返回值依据以下规则返回:

      • 如果then中的回调函数返回一个值,那么then返回的Promise将会成为接受状态,并且将返回的值作为接受状态的回调函数的参数值。
      • 如果then中的回调函数没有返回值,那么then返回的Promise将会成为接受状态,并且该接受状态的回调函数的参数值为 undefined。
      • 如果then中的回调函数抛出一个错误,那么then返回的Promise将会成为拒绝状态,并且将抛出的错误作为拒绝状态的回调函数的参数值。
      • 如果then中的回调函数返回一个已经是接受状态的Promise,那么then返回的Promise也会成为接受状态,并且将那个Promise的接受状态的回调函数的参数值作为该被返回的Promise的接受状态回调函数的参数值。
      • 如果then中的回调函数返回一个已经是拒绝状态的Promise,那么then返回的Promise也会成为拒绝状态,并且将那个Promise的拒绝状态的回调函数的参数值作为该被返回的Promise的拒绝状态回调函数的参数值。
      • 如果then中的回调函数返回一个未定状态(pending)的Promise,那么then返回Promise的状态也是未定的,并且它的终态与那个Promise的终态相同;同时,它变为终态时调用的回调函数参数与那个Promise变为终态时的回调函数的参数是相同的。

      描述

      由于 then 和 Promise.prototype.catch() 方法都会返回 promise,它们可以被链式调用 — 一种称为复合( _composition) _的操作.

      示例

      使用then方法

      let p1 = new Promise(function(resolve, reject) {
        resolve("Success!");
        // or
        // reject ("Error!");
      });
      
      p1.then(function(value) {
        console.log(value); // Success!
      }, function(reason) {
        console.log(reason); // Error!
      });
      
      

      链式调用

      then 方法返回一个Promise 对象,其允许方法链。

      你可以传递一个 lambda 给 then 并且如果它返回一个 promise,一个等价的 Promise 将暴露给后续的方法链。下面的代码片段使用 setTimout 函数来模拟异步代码操作。

      Promise.resolve("foo")
        // 1. 接收 "foo" 并与 "bar" 拼接,并将其结果做为下一个resolve返回。
        .then(function(string) {
          return new Promise(function(resolve, reject) {
            setTimeout(function() {
              string += 'bar';
              resolve(string);
            }, 1);
          });
        })
        // 2. 接收 "foobar", 放入一个异步函数中处理该字符串
        // 并将其打印到控制台中, 但是不将处理后的字符串返回到下一个。
        .then(function(string) {
          setTimeout(function() {
            string += 'baz';
            console.log(string);
          }, 1)
          return string;
        })
        // 3. 打印本节中代码将如何运行的帮助消息,
        // 字符串实际上是由上一个回调函数之前的那块异步代码处理的。
        .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");
      
          // 注意 `string` 这时不会存在 'baz'。
          // 因为这是发生在我们通过setTimeout模拟的异步函数中。
          console.log(string);
      });
      

      当一个值只是从一个 lambda 内部返回时,它将有效地返回 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,则调用将返回一个拒绝的Promise。

      Promise.resolve()
        .then( () => {
          // 使 .then() 返回一个 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( () => {
          // 使 .then() 返回一个 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() {
        // fetch() API 返回了一个 Promise.
        // 这个函数提供了类似的API,
        // 这个函数除了实现 Promise,它还能够完成更多的工作。
        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
      });
      

      规范

      规范状态备注
      ECMAScript 2015 (6th Edition, ECMA-262)Promise.prototype.thenStandardECMA标准的首次定义
      ECMAScript Latest Draft (ECMA-262)Promise.prototype.thenDraft 

      相关链接

      目录
      目录