Promise 对象用于异步调用返回值的集中处理。 Promise 对象表示一个现在将来永不可用的值。

语法

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

参数

executor
Promise构造器的参数,Function类型。该方法有2个参数:resolvereject,这两个参数均为方法类型executor 方法在调用Promise构造器时立即被调用(甚至在构造器方法返回新创建的Promise对象之前执行)。在executor内部,如果resolve被调用,代表该Promise被成功解析(resolve),而当reject被调用时,代表该Promise的值不能用于后续处理了,也就是被拒绝(reject)了。executor主要用于初始化异步代码, 一旦异步代码调用完成,要么调用resolve方法来表示Promise被成功解析,或是调用reject方法,表示初始化的异步代码调用失败,整个promise被拒绝。
如果在executor 方法的执行过程中抛出了任何异常,那么promise立即被拒绝(即相当于reject方法被调用),executor 的返回值也就会被忽略。
 

描述

Promise 对象是一个代理对象(代理一个值),被代理的值在Promise对象创建时可能是未知的。它允许你为异步代码执行结果的成功和失败分别绑定相应的处理方法(handlers )。 这让异步方法可以像同步方法那样返回值,但是并非立即返回执行的结果,因为毕竟执行的是异步代码,因此,它会返回一个Promise对象,如前所说,它是一个代理的对象,代理了最终返回的值,可以在后期使用

Promise有以下几种状态:

  • pending: 初始状态, 既不是 fulfilled 也不是 rejected.
  • fulfilled: 表示异步代码成功执行(没有错误抛出),且返回值已填充(fulfilled)
  • rejected: 表示executor执行失败,Promise被拒绝

pending状态的Promise对象可能被填充了(fulfilled)值,也可能被某种理由(异常信息)拒绝(reject)了。当其中任一种情况出现时,Promise对象的then方法绑定的处理方法handlers )就会被调用(then方法包含两个参数:onfulfilled和onrejected,它们都是Function类型。当值被填充时,调用then的onfulfilled方法,当Promise被拒绝时,调用then的onrejected方法, 所以在异步操作的完成和绑定处理方法之间不存在竞争)

因为Promise.prototype.then和 Promise.prototype.catch方法返回 promises对象自身, 所以它们可以被链式调用

注意: 有一些语言中有惰性求值和延时计算的特性, 它们也被称为"promises" --例如Scheme. Javascript中的promise代表一种已经发生的状态, 而且可以通过回调方法链在一起. 如果你想要的是表达式的延时计算, 考虑无参数的"箭头方法": f = () => 表达式 创建惰性求值的表达式, 使用 f() 求值.

注意: 如果一个promise对象处在fulfilled或rejected状态而不是pending状态,那么它也可以被称为settled状态。你可能也会听到一个术语resolved ,它表示promise对象处于settled状态,或者promise对象被锁定在了调用链中。关于promise的状态, Domenic Denicola 的 States and fates 有更多详情可供参考。

属性

Promise.length
长度属性,其值为 1 (构造器参数的数目).
Promise.prototype
表示 Promise 构造器的原型.

方法

Promise.all(iterable)
这个方法返回一个新的promise对象,该promise对象在iterable里所有的promise对象都成功的时候才会触发成功,一旦有任何一个iterable里面的promise对象失败则立即触发该promise对象的失败。这个新的promise对象在触发成功状态以后,会把一个包含iterable里所有promise返回值的数组作为成功回调的返回值,顺序跟iterable的顺序保持一致;如果这个新的promise对象触发了失败状态,它会把iterable里第一个触发失败的promise对象的错误信息作为它的失败错误信息。Promise.all方法常被用于处理多个promise对象的状态集合。(可以参考jQuery.when方法---译者注)
Promise.race(iterable)
当iterable参数里的任意一个子promise被成功或失败后,父promise马上也会用子promise的成功返回值或失败详情作为参数调用父promise绑定的相应句柄,并返回该promise对象。
Promise.reject(reason)
调用Promise的rejected句柄,并返回这个Promise对象。
Promise.resolve(value)
用成功值value完成一个Promise对象。如果该value为可继续的(thenable,即带有then方法),返回的Promise对象会“跟随”这个value,采用这个value的最终状态;否则的话返回值会用这个value满足(fullfil)返回的Promise对象。

Promise原型

属性

Promise.prototype.constructor
返回创建了实例原型的函数.  默认为 Promise 函数.

方法

Promise.prototype.catch(onRejected)
添加一个否定(rejection) 回调到当前 promise, 返回一个新的promise。如果这个回调被调用,新 promise 将以它的返回值来resolve,否则如果当前promise 进入fulfilled状态,则以当前promise的肯定结果作为新promise的肯定结果.
Promise.prototype.then(onFulfilled, onRejected)
添加肯定和否定回调到当前 promise, 返回一个新的 promise, 将以回调的返回值 来resolve.

示例

一个非常简单里的例子 (就10行!)

var myFirstPromise = new Promise(function(resolve, reject){
    //当异步代码执行成功时,我们才会调用resolve(...), 当异步代码失败时就会调用reject(...)
    //在本例中,我们使用setTimeout(...)来模拟异步代码,实际编码时可能是XHR请求或是HTML5的一些API方法.
    setTimeout(function(){
        resolve("成功!"); //代码正常执行!
    }, 250);
});

myFirstPromise.then(function(successMessage){
    //successMessage的值是上面调用resolve(...)方法传入的值.
    //successMessage参数不一定非要是字符串类型,这里只是举个例子
    console.log("Yay! " + successMessage);
});

创建Promise

本例展示了Promise的一些机制。 testPromise() 在每次点击 <button> 按钮时被调用,该方法会创建一个promise 对象,使用 window.setTimeout() 让Promise等待 1-3 秒不等的时间来填充数据(通过Math.random()方法)。

Promise 的值的填充过程都被日志记录(logged)下来,这些日志信息展示了方法中的同步代码和异步代码是如何通过Promise完成解耦的。

'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/>');

    // 新建一个Promise对象
    var p1 = new Promise(
        function(resolve, reject) {
            log.insertAdjacentHTML('beforeend', thisPromiseCount +
                ') Promise started (<small>Async code started</small>)<br/>');
            // 模拟异步代码
            window.setTimeout(
                function() {
                    // 填充(fulfilled))promise
                    resolve(thisPromiseCount);
                }, Math.random() * 2000 + 1000);
        }
    );

    // 通过调用then方法,我们定义了当promise被成功解析(resolved)/填充(fulfilled)时要执行的代码,
    // 而catch()方法则定义了当promise被拒绝(rejected)时要执行的代码.
    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。快速点击按钮多次你会可以观察到Promises填充值的过程是怎样的

使用XMLHttpRequest()的例子

创建一个Promise

这个例子展示了如何用promise报告一个XMLHttpRequest的成功或失败。

'use strict';

// A-> $http function is implemented in order to follow the standard Adapter pattern
function $http(url){
 
  // A small example of object
  var core = {

    // Method that performs the ajax request
    ajax : function (method, url, args) {

      // Creating a promise
      var promise = new Promise( function (resolve, reject) {

        // Instantiates the 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) {
            // Performs the function "resolve" when this.status is equal to 2xx
            resolve(this.response);
          } else {
            // Performs the function "reject" when this.status is different than 2xx
            reject(this.statusText);
          }
        };
        client.onerror = function () {
          reject(this.statusText);
        };
      });

      // Return the promise
      return promise;
    }
  };

  // Adapter pattern
  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);
    }
  };
};
// End A

// B-> Here you define its functions and its 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));
  }
};
// End B

// Executes the method call 
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success) 
  .catch(callback.error);

// Executes the method call but an alternative way (1) to handle Promise Reject case 
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success, callback.error);

// Executes the method call but an alternative way (2) to handle Promise Reject case 
$http(mdnAPI) 
  .get(payload) 
  .then(callback.success)
  .then(undefined, callback.error);

使用XHR加载图像

另一个用了PromiseXMLHttpRequest加载一个图像的例子可在MDN GitHub promise-test 中找到。 你也可以 see it in action。每一步都有注释可以让你详细的跟随了解Promise和XHR架构。

规范

规范 状态 备注
domenic/promises-unwrapping 草稿 标准化工作正在这里进行
ECMAScript 2015 (6th Edition, ECMA-262)
Promise
Standard ECMA标准中的首次定义

浏览器兼容性

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

参见

文档标签和贡献者

标签: 
 最后编辑者: liujun121533,