基础

ES6原生提供了Promise对象,用来保存某个异步操作的结果。其状态不受外界影响,且状态一旦改变,就不会再变化。

可能的状态:

  • pending 进行中
  • fulfilled 已成功
  • rejected 已失败

状态改变:

  • pending-->fulfilled
  • pending-->rejected

状态一旦发生改变就会定型,称为resolved。如果改变已经发生,再对Promise对象添加回调函数,也会立即得到这个结果。

Promise创建后无法取消,pending状态下也无法得知进度。

创建Promise实例:

const promise = new Promise(function(resolve, reject){
    .....
    if (/*操作成功*/) {
        resolve(value);
    } else {
        reject(error);
    }
}); 

其中,Promise参数为一个函数,函数的两个参数分别是JS提供的resolvereject函数;

resolve函数将Promise状态变为resolved;在异步操作成功时调用,并将异步操作的结果作为参数传递出去;

reject函数将Promise状态变为rejected;在操作失败时调用,并将操作失败报出的错误,作为参数传递出去。

设置这两个函数的回调函数

promise.then(function (value){
    // 成功回调
}, function (error) {
    // 失败回调
});

一个Ajax实例

const getJson = function (url) {
        const promise = new Promise(function(resolve, reject){
          const handler = function () {
            if (this.readyState !== 4) {
              return;
            }
            if (this.status === 200) {
              resolve(this.responseText);
            } else {
              reject(new Error(this.statusText));
            }
          }
          const XHR = new XMLHttpRequest();
          XHR.open("GET", url, true);
          XHR.responseType = "json";
          XHR.onreadystatechange = handler;
          XHR.setRequestHeader("Accept", "application/json");
          XHR.send()
        });
        return promise;
      }
      getJson("posts.json").then(function(json){
        console.log("Contents: "+json);
      }, function (error) {
        console.error("Error: ", error);
      });

Promise.prototype.then()

Promise实例添加状态改变时的回调函数,返回一个新的Promise对象,可以采用链式写法,指定一组按照次序调用的回调函数;

注意then()方法必须接收一个函数作为参数,否则then()方法就会被视为then(null),不会起作用.

// 以下输出为1
      Promise.resolve("1").then(Promise.resolve("2")).then(Promise.resolve("3"))
      .then(function (value) {
        console.log(value);
      });

Promise.prototype.catch()

`then(null, rejection)的别名。用于指定发生错误时的回调函数;

Promise对象的错误具有冒泡性质,出现错误后会不停向后传递直到被捕获为止;但如果没有用catch方法指定回调函数,Promise对象内部的错误不会传递到外部;

一般建议Promise对象后面要跟catch方法,这样可以处理Promise对象内部的错误;该方法返回的还是一个Promise对象。

建议在then方法中定义resolve方法,而在catch方法中定义Reject状态的回调函数。

promise.then(function (value) {
    //resolve函数
}).catch(function (error) {
    //reject函数
});

Promise.prototype.finally()

添加不论Promise对象最终的状态是Resolved还是Rejected都会执行的函数;

Promise.all()

用于把多个Promise实例,包装成一个新的Promise实例。参数必须是有Iterator接口的结构,且返回的成员都为Promise实例。对于数组参数,如果有不是Promise对象的项,会先调用promise.resolve()方法将其转为Promise对象。

参数中所有的Promise对象的状态是逻辑与的关系,只有都变成了fulfilled,总的Promise对象的状态才会变成fulfilled,所有返回值组成数组传给总对象的回调函数;

而只要有一个是rejected,总的Promise对象也会变为rejected,第一个被reject的实例的返回值被传给总对象的回调函数。

Promise.race()

同样是将多个Promise对象包装成一个Promise对象,但是参数对象只要有一个状态发生改变,总函数对象就会跟着改变,并把这个参数对象的返回值传递给总对象的回调函数;

Promise.resolve()

参数情况:

  • Promise实例--该方法直接返回该实例;
  • 不是Promise实例,但具有then方法--把该对象变成Promise实例,并立即执行其then方法;
  • 不是具有then方法的对象--返回一个新的Promise对象,状态为resolved,参数会传给回调函数;
  • 没有参数--直接返回一个resolved状态的Promise对象;

关于执行时机:

立即resolve的Promise对象是在本轮“事件循环”结束时,而不是下一轮“事件循环”开始时;(setTimeout()的回调函数是下一轮“事件循环”开始时)。

      setTimeout(function () {console.log("setTimeout out1")}, 0);
      Promise.resolve().then(function () {
        console.log("Promise out1");
      });
      console.log("direct 1");
      setTimeout(function () {console.log("setTimeout out2")}, 0);
      Promise.resolve().then(function () {
        console.log("Promise out2");
      });
      console.log("direct 2");

      // direct out1
      // direct out2
      // Promise out1
      // Promise out2
      // setTimeout out1
      // setTimeout out2

Promise.reject()

该方法返回一个状态为rejected的Promise对象,并把参数直接传递给回调函数,立即执行。

Promise.try()

模拟try代码块,可以捕捉同步或异步的错误:

Promise.try(function () {
    ......
}).then(function (value) {
    ......
}).catch(function (error) {
    ......
})

Promise的深入理解

参考:We have a problem with promises

  1. Promise对象的then()方法会返回一个新的Promise对象,then()方法的参数如果不是函数,会直接被视为then(null)对待;

  2. 作为.then()方法的参数的函数中,如果没有使用return返回某些值,将不会把结果输出到下一个方法中(undefined),该方法变成同步方法,下一个then中的回调函数将不会等待这个函数执行结束;建议始终在then()方法的参数中始终使用returnthrow

  3. 可能返回的合理的值包括:

    • 一个新的Promise对象;
    • 一个同步的值;
    • 抛出一个同步的错误;
  4. 使用Promise.resolve()Promise.reject(), 可以方便地返回一个立即resolvedrejected的Promise对象,用其封装一些同步方法可以很好地管理then()和捕捉错误;

function somePromiseAPI() {
    return Promise.resolve().then(function () {
        doSomeThingThatMayThrow();
        return "foo";
    }).then(/*.......*/);
}
  1. then(resolve, reject)中的reject回调函数只捕捉调用then()的Promise对象内的错误,而不会捕捉resolve函数中的错误;而.then(resolve, reject).catch(function (erroe)...)可以捕捉Promise对象和回调函数中的错误;

2018-5-26

 posted on 2018-06-18 21:26  木汀  阅读(103)  评论(0编辑  收藏  举报