Es6中Promise的详情介绍

Promise

目录:

一.promise简介
1) 什么是Promise
2) 解决哪些问题
3) 如何使用
二.promise用法
1) then的链式操作
三.基于promise发送Ajax请求
四.promise基于API
1)catch的用法
五.promise的静态方法
六.promise状态的变化

一. promise简介

什么是Promise:

所谓Promise,简单来说就是一个容器, 里面保存着某个未来才会结束的事件(通常是一个异步操作)的结果。从语法上来说,Promise是一个对象,它可以获取异步操作的消息; Promise提供统一的API, 各种异步操作都可以用同样的方法进行处理;

Promise是异步编程的一种解决方案;它是一个对象,用于获取异步操作; Promise有三种状态: pending(等待)、fulfilled(成功)、rejected(失败); 状态一旦改变就不会再变, Promise实例创建后,会立即执行;

let promise = new Promise(function(resolve, reject) {
  console.log('Promise');
  resolve();
});

promise.then(function() {
  console.log('resolved.');
});

console.log('Hi!');

// Promise
// Hi!
// resolved
// Promise 新建后立即执行,所以首先输出的是Promise。然后,then方法指定的回调函数,将在当前脚本所有同步任务执行完才会执行,所以resolved最后输出

能够解决哪些问题:

  1. 解决回调地狱(异步深层嵌套)问题,代码难以维护,现象: 第一个函数的输出是第二个函数的输入;
    2. Promise可以支持多个并发的请求, 获取并发请求中的数据;
    3. 这个Promise可以解决异步问题,本身不能说Promise是异步的;

如何使用:

由于Promise是一个构造函数, 所以使用时直接new一个即可:

let  p  =   new  Promise((resolve, reject) => {
>     // 内部是异步函数
>   });

二.Promise基本用法

Promise是一个构造函数, 自身方法: all、reject、resolve等, 原型上有then、catch等方法;

<script type="text/javascript"> 
    /*
      1. Promise的基本使用
        我们使用new来构建一个Promise, Promise的构造函数接收一个参数,是函数,并且传入两个参数:
        resolve, reject, 分别表示异步操作执行成功后的回调函数  和  异步操作执行失败后的回调函数;
    */ 
    var p = new Promise ((resolve, reject) => {
      // 2. 这里用于实现异步任务  
      setTimeout( () => {
          var flag = false
          if (flag) {
              // 3. 正常情况
              resolve('hello')
          } else {
              // 4. 异常情况
              reject('出错了')
          }
      }, 1000)
    });
    // 打印结果: 报错 '出错了'

    // 5. Promise实例生成之后, 可以用then方法指定resolved状态和reject状态的回调函数
    // 在then方法中, 也可以直接return数据而不是Promise对象, 在后面的then中就可以接收到数据了;
    p.then((data) => {
        // then的第一个参数接收函数执行成功的结果
        console.log(data)
    },(info) => {
        // then的第二个参数接收函数执行失败的结果
      console.log(info)
    })
  </script>

Promise的构造函数接收一个参数, 这个参数是一个函数, 函数中需要传入两个参数,它们也是两个函数,由JavaScript 引擎提供,不用自己部署。

resolve: 异步操作执行成功后的回调函数
reject: 异步操作执行失败后的回调函数

resolve函数的作用是,将Promise对象的状态从“未完成”变为“成功”(即从 pending 变为(resolved),在异步操作成功时调用,并将异步操作的结果,作为参数传递出去;

reject函数的作用是,将Promise对象的状态从“未完成”变为“失败”(即从 pending 变为
rejected),在异步操作失败时调用,并将异步操作报出的错误,作为参数传递出去。

如果调用resolve函数和reject函数时带有参数,那么它们的参数会被传递给回调函数。reject函数的参数通常是Error对象的实例,表示抛出的错误;resolve函数的参数除了正常的值以外,还可能是另一个
Promise 实例,比如像下面这样。

const p1 = new Promise(function (resolve, reject) {
  // ...
});

const p2 = new Promise(function (resolve, reject) {
  // ...
  resolve(p1);
})
/*
  p1和p2都是 Promise 的实例,但是p2的resolve方法将p1作为参数,即一个异步操作的结果是返回另一个异步操作。

注意,这时p1的状态就会传递给p2,也就是说,p1的状态决定了p2的状态。
     如果p1的状态是pending,那么p2的回调函数就会等待p1的状态改变;
     如果p1的状态已经是resolved或者rejected,那么p2的回调函数将会立刻执行。
*/

进一步说明:

const p1 = new Promise(function (resolve, reject) {
  setTimeout(() => reject(new Error('fail')), 3000)
})

const p2 = new Promise(function (resolve, reject) {
  setTimeout(() => resolve(p1), 1000)
})

p2
  .then(result => console.log(result))
  .catch(error => console.log(error))
// Error: fail

/*
  上面代码中,p1是一个 Promise,3 秒之后变为rejected。
             p2的状态在 1 秒之后改变,resolve方法返回的是p1。
             由于p2返回的是另一个 Promise,导致p2自己的状态无效了,由p1的状态决定p2的状态。
             所以,后面的then语句都变成针对后者(p1)。
             又过了 2 秒,p1变为rejected,导致触发catch方法指定的回调函数。
*/
Promise.prototype.then()

Promise实例具有then方法, 也就是说then方法是定义在原型对象 Promise.prototype上的;
它的作用是为Promise实例添加状态改变时的回调函数; then方法的第一个参数是resolved状态的回调函数,
第二个参数(可选)是rejected状态的回调函数;

then方法返回的是一个新的Promise实例(注意: 不是原来那个Promise实例)。因此可以采用链式写法, 即then方法后面再调用另一个then方法。

  1. then方法可以接收两个参数,第一个对应resolve的回调, 第二个对应reject的回调. 所以我们能够分别拿到它们传递过来的数据;
  2. then方法中也可以只写一个参数, resolve, 一般是处理正确的结果(这种情况下一般失败的结果由catch来接收);
 /*
  getJSON("/post/1.json").then(function(post) {
    return getJSON(post.commentURL);
  }).then(function (comments) {
    console.log("resolved: ", comments);
  }, function (err){
    console.log("rejected: ", err);
  });
*/

/*
  上面代码中,第一个then方法指定的回调函数,返回的是另一个Promise对象。
  这时,第二个then方法指定的回调函数,就会等待这个新的Promise对象状态发生变化。
  如果变为resolved,就调用第一个回调函数,如果状态变为rejected,就调用第二个回调函数
*/

// 如果采用箭头函数,上面的代码可以写得更简洁。

getJSON("/post/1.json").then(
  post => getJSON(post.commentURL)
).then(
  comments => console.log("resolved: ", comments),
  err => console.log("rejected: ", err)
);

三.基于Promise发送Ajax请求

<script type="text/javascript">
    // 基于Promise发送Ajax请求
    function queryData(url) {
      // 1. 创建一个Promise实例
      var p = new Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = () => {
            if(xhr.readyState != 4) return
            if(xhr.readyState == 4 && xhr.status == 200) {
                // 2. 处理正常的情况
                resolve(xhr.responseText)
            } else {
              // 3. 处理异常情况
              reject('服务器错误')
            }
        };
        xhr.open('get', url)
        xhr.send(null)
      });
      return p;
    }
    // 注意: 这里需要开启一个服务
    // 在Promise中,then主要用于处理函数执行的结果(包括失败的和成功的)
    // 在then方法中,可以直接renturn数据而不是Promise对象,在后面的then中就可以接收数据了
    queryData('http://localhost:3000/data')
    .then((data) => {
      console.log(data)
      // 4. 想要继续链式编程走下去 需要return
      return queryData('http://localhost:3000/data1')
    }).then((data) => {
      console.log(data)
      return queryData('http://localhost:3000/data2')
    }).then((data) => {
        console.log(data)
    });
  </script>

四.Promise基于API

.then()
// 得到异步任务正确的结果
.catch()
// 获取异常信息
.finally()
// 成功与否都会执行(不是正式标准)

<script type="text/javascript">
    // console.dir(Promise)
    function foo() {
      return new Promise((resolve, reject) => {
        setTimeout(() => {
          // resolve(123)
          reject('error')
        }, 1000)
      })
    }
    // ------------------------------------
    // foo()
    // .then((data) => {
    //   // 此时的then处理函数执行成功的结果
    //   console.log(data)
    // })
    // .catch((data) => {
    //   // catch处理函数执行失败的结果
    //   console.log(data)
    // })
    // .finally((data) => {
    //   // 处理函数执行的结果(包括失败结果和成功结果)
    //   console.log('finished')
    // })
    // -----------------------------------------------

    // 两种写法是等效的
    foo()
    .then((data) => {
      // 得到异步任务正确的结果
      console.log(data);
    },(data) => {
      // 获取异常信息
      console.log(data)
    })
    // 成功与否都会执行
    .finally(() => {
      console.log('finashed')
    })
  </script>
Promise.prototype.catch()

Promise.prototype.catch方法是.then(null, rejection)或.then(undefined, rejection)的别名,用于指定发生错误时的回调函数。

  1. caatch和then接收第二个参数一样, 用来指定reject的回调, 接收执行的错误结果;
  2. 在执行reslove的回调(then的第一个参数时), 如果抛出异常了, 那么并不会报错卡死, 而是会进入这个catch方法中;

五.Promise的静态方法

.all()
Promise.all方法接受一个数组作为参数, 数组中的对象(p1、p2、p3)均为promise实例(如果不是一个promise, 该项会被用Promise.resolve转换为一个promise); 它的状态由这三个promise实例决定;
.race()
Promise.race方法同样接受一个数组做参数, 当p1、p2、p3中有一个实例的状态发生改变(变为fulfilled或者rejected), p的状态就跟着改变; 并把第一个改变状态的promise的返回值, 传给p的回调函数;

<script type="text/javascript">
  /*
      Promise常用API-对象方法
    */
    //  console.dir(Promise)
    function queryData(url) {
      return Promise((resolve, reject) => {
        var xhr = new XMLHttpRequest();
        xhr.onreadystatechange = function() {
          if (xhr.readyState != 4) return;
          if(xhr.readyState == 4 && xhr.status == 200) {
            // 处理正常情况
            resolve(xhr.responseText);
          } else {
            // 处理异常情况
            reject('服务器错误');
          }
        }
        xhr.open('get', url);
        xhr.send(null)
      })
      var p1 = queryData('http://localhost:3000/a1');
      var p2 = queryData('http://localhost:3000/a2');
      var p3 = queryData('http://localhost:3000/a3');
      Promise.all([p1,p2,p3]).then(function(result) {
        //   all 中的参数  [p1,p2,p3]   和 返回的结果一 一对应["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
         console.log(result) //["HELLO TOM", "HELLO JERRY", "HELLO SPIKE"]
      })
    }
    Promise.race([p1,p2,p3]).then((result) => {
      // 由于p1执行较快,Promise的then()将获得结果'P1'。p2,p3仍在继续执行,但执行结果将被丢弃;
      console.log(result) // "HELLO TOM"
    })
</script>

六.Promise状态的变化

  1. Promise对象的状态不收外界影响,Promise对象代表一个异步操作, 有三种状态: pending(进行中)、fulfilled(已成功)、rejected(已失败); 只有异步操作的结果可以决定当前是哪一种状态,其他任何操作都无法改变这个状态;

  2. 一旦状态改变,就不会再变,任何时候都可以得到这个结果;同一时间下只能存在一种状态; Promise对象的状态改变,只有两种可能:从pending变为fulfilled和从pending变为rejected。只要这两种情况发生,状态就凝固了,不会再变了,会一直保持这个结果,这时就称为 resolved(已定型);

    1. 初始化状态: pending;
    2. 当调用resolve(成功),状态: pending => fulfilled;
    3. 当调用reject(失败), 状态: pending => rejected;
 const PNEDING = "pending";  
 //  Promise会一直保持挂起状态, 直到被执行(成功)或者拒绝(失败);
 const FULFULLED = "fulfilled";
 const REJECTED = "rejected";
 class Promise {
   const ructor (exector){
     let self = this;//缓存当前promise对象
     self.status = PENDING;//初始状态,对promise对象调用state(状态)方法,可以查看其状态是“pending"、"resolved"、还是”rejected“
     self.value = undefined;// fulfilled状态时 返回的信息
     self.reason = undefined;// rejected状态时 拒绝的原因
     self.onResolveCallBacks = [];// 存储resolve(成功)状态对应的onFulfilled函数
     self.onRejectCallBacks = [];// 存储rejected(失败)状态对应的onRejected函数
     let resolve = (value) => {//成功
        if(self.status === PENDING){//如果成功则,状态由pending=>fulfilled
          self.status = FULFULLED;
          self.value = value;
          self.onResolveCallBacks.forEach(cb=>cb(self.value));//执行发布
         }
      }

      let reject = (reason) => {//失败
         if(self.status === PENDING){//如果失败,则状态由pending=>rejected
            self.status = REJECTED;
            self.reason = reason;            self.onRejectCallBacks.forEach(cb=>cb(self.reason));//执行发布
          }
      }

      try{
         exector(resolve,reject)                 
      }catch(e){
         reject(e)
      }

   }
   then(onFulfilled,onRejected){
        let self=this;
        if(self.status === FULFULLED){
            onFulfilled(self.value);//成功值
        }
        if(self.status === REJECTED){
            onFulfilled(self.reason);//拒绝原因
        }
        if(self.status === PENDING){
            self.onResolveCallBacks.push(onFulfilled);//订阅发布
            self.onRejectCallBacks.push(onRejected);//订阅发布
        }
    }
    /*
      promise的决议结果只有两种可能:完成和拒绝,附带一个可选的单个值。
      如果Promise完成,那么最终的值称为完成值;
      如果拒绝,那么最终的值称为原因。
      Promise只能被决议(完成或拒绝)一次。
      之后再次试图完成或拒绝的动作都会被忽略;
    */
 }
 new Promise((resolve,reject)=>{
    resolve("成功时调用")//异步处理
    //处理结束后、调用resolve或reject
}).then((data)=>{
    console.log(data);//"成功"
},(reason)=>{
    console.log(reason);
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值