ES6中的Promise

最近看了下ES6中Promise对象的用法,觉得他是一个好东西,使代码的书写变得可读性更高,解决了在请求资源时,一个数据的获取要依赖上一个请求所获取的数据,如果不用Promise就会使代码嵌套看起来很复杂的问题,继而可读性,可维护性都会降低,然而用了Promise之后,代码逻辑顺序看起来就会很清晰。


一. Promise的基本用法

function getPromise(cont) {
    var promise = new Promise(function (resolve, reject) {
        if (cont) {
            resolve("Hello!");
        } else {
            reject("Good bye!");
        }
    });
    return promise;
}

getPromise(true).then(function (success){
    console.log(success);  //输出hello
},function (error){
    console.log(error);
})

在使用Promise时首先创建一个Promise对象,对象的参数是一个函数,函数里面的两个参数,一个是成功时的执行方法(resolve),一个是失败时的执行方法(reject)。接下来就可以用then()方法去获取Promise执行结果的返回值了,如果成功就输出传入resolve()方法的参数,失败就输出传入reject()方法的参数,这是上面代码的执行流程。Promise有三个状态,分别是:

  • Resolved:成功状态;
  • Rejected:失败状态;
  • Pending:Promise实例被创建时的初始状态,该状态不可获取。

在执行then()方法时还有另一种操作,可以使代码看起来更加简洁,意思表达更加明确,即可以使用catch()方法;

getPromise(false).then(function (success){
    console.log(success);
}).catch(function (error){
    console.log(error);  //Good bye!
});

catch()方法是执行结果出错时调用的方法,就相当于 getPromise(false).then(function(success){}, null).catch()


二. Promise的链式调用

就像刚开始所说的那样,当我们在获取数据时,如果后一个操作需要前一个操作响应成功后的参数,如果用ajax异步加载,就会使代码看起来嵌套很复杂(脑补下),但是用了Promise后代码就会看起来很清晰。

随便举个例子,我们先从服务器获得用户名,然后获取用户的详细信息,需要两次异步操作,第一次或许用户名,第二次获取用户详细信息,下面是代码实现:

/*获取用户名的执行函数*/
function getUsername(){
      var promise = new Promise(function(resolve, reject){
        var req = getRequest();
        if (req != null){
          req.open("get", "/username", true);
          req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
          req.onreadystatechange = function(){
            if (req.readyState == 4){
              resolve(req.responseText);  //将用户名传入
            } else{
              setTimeout(function(){
                reject("出错了!");  //传入出错信息
              }, 1000);
            }
          };
          req.send();
        }
      });
      return promise;
    }

/*获取用户详细信息的执行函数*/
    function getUsermess(username){
      var promise = new Promise(function(resolve, reject){
        var req = getRequest();
        if (req != null){
          req.open("get", "/usermess?name=username", true);
          req.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
          req.onreadystatechange = function(){
            if (req.readyState == 4){
              resolve(req.responseText);  //传入用户详细信息
            } else{
              setTimeout(function(){
                reject("出错了!");  //出错信息
              }, 1000);
            }
          };
          req.send();
        }
      });
      return promise;
    }
/*某时间触发后的执行方法*/
  function handler(){
      getUsername().then(function (name){
          return getUsermess(name);
      }).then(function (mess) {
          console.log(mess);
      }).catch(function (error) {
          console.log(error);
      });
    }

上面的代码用了原生的ajax,在代码中用了Promise来将执行的返回结果,传给另一个异步请求,然后进而获得下一步要获取的数据。可以看出用了Promise的链式调用then()方法后代码的逻辑看起来很清晰。

then()方法的返回值是一个Promise对象,它可以将上一步的返回结果传给传给下一个then()方法调用:

getPromise(true).then(function (success){
    return success;
}).then(function (message){
    console.log(message + "nihao!"); //Hello!nihao!
}).catch(function (error){
    console.log(error);
});

这样就算我们不需要嵌套请求时,在第一个then()方法返回我们要获取的数据,第二个里面就可以对数据进行解析,并添加到页面中,可以使数据的获取与表示分离。


三. Promise.all()方法和Promise.race()方法

Promise.all()和Promise.race()方法都接收一个Promise对象的数组作为参数,不同的是all()方法在所有Promise对象都执行完毕时才会返回,而race()方法是只要有一个执行完毕就会返回。当我们要从不同的服务器路径去获取资源,然后所有的资源整合在一起显示时,这时all()方法就会很有用,假设用户的图像和用户信息不在同一路径下,但要一起显示:

function getUserpic(){
      var promise = new Promise(function(resolve, reject){
        var req = getRequest();
        if (req != null){
          req.open("post", "/userpic", true);
          req.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
          req.onreadystatechange = function(){
            if (req.readyState == 4){
              resolve(req.responseText);
            } else{
              setTimeout(function(){
                reject("出错了!");
              }, 1000);
            }
          };
          req.send();
        }
      });
      return promise;
    }

    function getUsermess(){
      var promise = new Promise(function(resolve, reject){
        var req = getRequest();
        if (req != null){
          req.open("post", "/usermess", true);
          req.setRequestHeader("Content-type", "application/x-www-form-urlencoded")
          req.onreadystatechange = function(){
            if (req.readyState == 4){
              resolve(req.responseText);
            } else{
              setTimeout(function(){
                reject("出错了!");
              }, 1000);
            }
          };
          req.send();
        }
      });
      return promise;
    }

    function handler(){
      Promise.all([getUserpic(), getUsermess()]).then(function(message){
          console.log(message);
      }).catch(function(error){
        console.log(error);
      });
    }

这是我自己试了之后打印出的值:
这里写图片描述

可以看出打印出来的是个数组,接下来就可以去解析数组完成在页面的显示了。


上面是我对Promise对象的初步认识,还有看得仔细的在上面的代码中,如何请求错误我设置了一个延时,这是因为如果不设置代码的执行结果就一直是出错,这是因为请求还没有响应成功,reject()就执行了,所以就加个定时器来等服务器响应成功再执行rejecet()方法。

-------------本文结束感谢您的阅读-------------