Promise基础(上)

  • Post author:
  • Post category:其他



目录

一:

Promise是什么?

二:为什么要是用Promise?

三:Promise体验(随机数抽奖小案例)

四:Promise实践练习

五:Promise的状态改变

六:Promise的基本流程

七:如何使用Promise?

八:Promise的几个关键问题

一:

Promise是什么?

1. 抽象表达:

1):Promise是一门新的技术(ES6)规范

2):Promise是JS中进行异步编程的新解决方案(备注:旧的解决方案是单纯使用回调函数)

2. 具体表达:

1):从语法上来说:Promise是一个构造函数

2):从功能上来说:Promise对象用来封装一个异步操作并可以获取其成功/失败的结果值

扩展:异步编程(包括但不限于以下)

  1. fs :文件操作(node.js下面的一个模块,对计算机磁盘进行读写操作)

    require('fs').readFile('./index.html',(err,data)=>{})
  2. 数据库操作(例如:MySQL)
  3. AJAX

    $.get('/server',(data)=>{})
  4. 定时器

    setTimeout(()=>{},time)

二:为什么要是用Promise?

1.指定回到函数的方式更灵活

  • 1):旧的:必须在启动异步任务前指定
  • 2):Promise:启动异步任务===》返回Promise对象===》给Promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)

2.支持链式调用,可以解决回调地域问题

1):什么是回调地狱?

  • 回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件

    asyncFunc1(opt,(...args1)=>{
        asyncFunc2(opt,(...args2)=>{
            asyncFunc3(opt,(...args3)=>{
                asyncFunc4(opt,(...args4)=>{
                    //some operation
                })
            })
        })
    })

2):回调地狱的缺点?

  • 不便于阅读
  • 不便于异常处理

3):解决方案?

  • Promise链式调用

4):终极解决方案?

  • async / await

三:抽奖小案例

 <body>
    <button id="btn">点击抽奖</button>
    <script>
      //生成随机数
      function rand(m, n) {
        return Math.ceil(Math.random() * (n - m + 1)) + m - 1;
      }
      /*
        点击按钮  ,2s后显示是否中奖(30%概率中奖)
            若中奖弹出:恭喜恭喜,奖品为10万RMB劳斯莱斯优惠券
            若未中奖弹出:再接再厉
      */
      //获取元素对象
      const btn = document.getElementById("btn");
      // 绑定单击事件
      btn.onclick=function () {
        //30%中奖概率
        // setTimeout(() => {
        //   let num = rand(1, 100);
        //   if (num <= 30) {
        //     alert("恭喜恭喜,奖品为10万RMB劳斯莱斯优惠券"+',中奖号码为'+num);
        //   } else {
        //     alert('再接再厉'+',您的号码为'+num);
        //   }
        // }, 1000);

        //Promise形式实现
        //resolve 解决  (函数类型的数据)
        // reject 拒绝  (函数类型的数据)
        const P = new Promise((resolve, reject) => {
          setTimeout(() => {
            let num = rand(1, 100);
            if (num <= 30) {
              resolve(num);//调完之后可以将Promise对象(P)的状态设置为【成功】
            } else {
              reject(num);//调完之后可以将Promise对象(P)的状态设置为【失败】
            }
          }, 1000);
        });
        //调用then方法
        P.then(
          (value) => {
            alert("恭喜恭喜,奖品为10万RMB劳斯莱斯优惠券,您的中奖号码为:"+value);
          },
          (reason) => {
            alert("再接再厉,您的号码为:"+reason);
          }
        );
      };
    </script>
  </body>

四:实践练习

  1. fs基础(在node.js环境下运行;例如:node   xxx.js(就是下方代码所在的js文件))

    const fs = require("fs");
    // 回调函数形式
    // fs.readFile('./resource/content.txt',(err,data)=>{
    //     // 如果出错就抛出错误
    //     if(err) throw error;
    //     // 输出文件内容(BUffer类型)
    //     console.log(data);
    //     // 输出文件内容(转为字符串)
    //     console.log(data.toString());
    // })
    
    // Promise 形式
    const P = new Promise((resolve, reject) => {
      fs.readFile("./resource/content.txt", (err, data) => {
        if (err) reject(err);
        resolve(data);
      });
    }).then(
      (value) => {
        console.log(value.toString());
      },
      (reason) => {
        console.log(reason);
      }
    );
  2. ajax请求

      <body>
        <button id="btn">点击发送AJAX</button>
        <script>
          // 接口地址:https://api.apiopen.top/getJoke
          const btn = document.getElementById("btn");
          btn.onclick = function () {
            //创建Promise
            const P = new Promise((resolve, reject) => {
              // 创建对象
              let xhr = new XMLHttpRequest();
              //设置返回数据为json格式
              xhr.responseType='json'
              // 初始化
              xhr.open("GET", "https://api.apiopen.top/getJoke");
              // 处理响应
              xhr.onreadystatechange = function () {
                if (xhr.readyState === 4) {
                  // 5.判断响应状态码
                  if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response);
                  } else {
                    reject(xhr.status);
                  }
                }
              };
              // 发送
              xhr.send();
            }).then(
              (value) => {
                console.log(value);
              },
              (reason) => {
                console.warn(reason);
              }
            );
            // 创建对象
            // let xhr = new XMLHttpRequest();
            //设置返回数据为json格式
               xhr.responseType='json'
            // // 初始化
            // xhr.open("GET", "https://api.apiopen.top/getJoke");
            // // 处理响应
            // xhr.onreadystatechange = function () {
            //   if (xhr.readyState === 4) {
            //     // 5.判断响应状态码
            //     if (xhr.status >= 200 && xhr.status < 300) {
            //       //控制台输出响应体
            //       console.log(xhr.response);
            //     } else {
            //       //控制台输出错误的响应码
            //       console.log(xhr.status);
            //     }
            //   }
            // };
            // // 发送
            // xhr.send();
          };
        </script>
      </body>
    

    3. 封装fs文件(mineReadFile)

    function mineReadFile(path) {
      return new Promise((resolve, reject) => {
        //读取文件
        require("fs").readFile(path, (err, data) => {
          //判断
          if (err) reject(err);
          resolve(data);
        });
      });
    }
    mineReadFile("./resource/content.txt").then(
      (value) => {
        //输出文件内容
        console.log(value.toString());
      },
      (reason) => {
        console.log(reason);
      }
    );

    4. util.promisify(original)   (node.js下面的一个模块,传入一个遵循常见的错误优先的回调风格的函数)

    // 引入util模块
    const util = require('util');
    // 引入fs
    const fs = require('fs')
    //返回一个新的函数
    let mineReadFile = util.promisify(fs.readFile) 
    mineReadFile('./resource/content.txt').then(value=>{
        console.log(value.toString());
    })

    5.封装AJAX

    function sendAJAX(url) {
       return new Promise((resolve, reject) => {
          let xhr = new XMLHttpRequest();
          xhr.responseType='json'
          xhr.open("GET", "https://api.apiopen.top/getJoke");
          xhr.onreadystatechange = function () {
             if (xhr.readyState === 4) {
                if (xhr.status >= 200 && xhr.status < 300) {
                    resolve(xhr.response);
                  } else {
                    reject(xhr.status);
                  }
                }
          };
          xhr.send();
       });
    }
    sendAJAX("https://api.apiopen.top/getJoke")
    .then(value => {console.log(value);},(reason) => {console.warn(reason);});

五:

1.promise对象状态属性介绍【promiseState】

  • pending变为resolved/fulfilled(成功)
  • pending变为rejected(失败 )

说明:只有这两种,且一个promise对象只能改变一次;无论变为成功还是失败,都会有一个结果数据;成功的结果数据一般为value,失败的结果数据一般称为reason

2. promise对象结果值属性介绍【promiseResult】

  • 保存的是异步任务:对象[ 成功 / 失败 ] 的结果
  • 只有resolve()和reject()   可以对其改变赋值

六:Promise的基本流程

七:如何使用Promise?

一. API

1.Promise构造函数:Promise(excutor){}

(1): excutor函数:执行器 (resolve,reject)=>{ };

(2):resolve函数:内部定义成功时我们调用的函数  value =>{ };

(3):reject函数:内部定义成功时我们调用的函数  reason=>{ };

说明:excutor会在Promise内部立即同步调用,异步操作在执行器中执行。

let P = new Promise((resolve,reject)=>{
    //同步执行
    console.log('11111')
})
console.log('22222')
//打印结果:
//11111
//22222

2. Promise.prototype.then方法:(onResolved,onRejected)=>{ }

(1):onResolved函数:成功的回调函数  (value)=>{ };

(2): onRejected函数:失败的回调函数  (reason)=>{ };

说明:指定用于得到成功:value的成功回调和用于得到失败:reason的失败回调,返回一个新的promise对象

3. Promise.prototype.catch 方法:(onRejected)=>{ }

(1):onRejected函数:失败的回调函数  (reason)=>{ };

let P = new Promise((resolve, reject) => {
        resolve("error");
      });
      P.catch((reason) => {
        console.log(reason);//error
      });

4. Promise.resolve 方法:(value)=>{ };

(1):value:成功的数据 或 promise对象

说明:返回一个成功/失败的promise对象

let P1 = Promise.resolve("promise");
//如传入的参数为 非promise类型的对象,则返回的结果为成功promise对象
console.log(P1);//返回的结果如下图 (左边)

let P2 = Promise.resolve(new Promise((resolve,reject)=>{
    resolve('OK')
}));
//如传入的参数为promise对象,则参数的结果决定了resolve的结果
console.log(P2);//返回的结果如下图 (右边)


5. Promise.reject 方法:(reason)=>{ };

(1):reason:失败的原因

说明:返回一个失败的promise对象

let P = Promise.reject(996);
let P2 = Promise.reject("promise");
let P3 = Promise.reject((resolve, reject) => {
    resolve("OK");
});
//无论传入什么,结果都是失败
console.log(P,P2,P3); //结果如下图

6. Promise.all 方法:(promise)=>{ };

(1):promise:包含n个promise的数组

说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一个失败了就直接失败

//全部成功
let P = new Promise((resolve, reject) => {
    resolve("OK");
});
let P2 = Promise.resolve("success");
let P3 = Promise.resolve("Yes");

const result = Promise.all([P, P2, P3]);
console.log(result);//全部成功的结果如下图(左边)

//有失败
let P = new Promise((resolve, reject) => {
    resolve("OK");
});
let P2 = Promise.resolve("success");
let P3 = Promise.resolve("Yes");
let P4 = Promise.reject("error");

const result = Promise.all([P, P2, P3,P4]);
console.log(result);//有失败的结果如下图(右边)


7. Promise.race方法:(promise)=>{ };

(1):promise:包含n个promise的数组

说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

let P = new Promise((resolve, reject) => {
    resolve("OK");
});
let P2 = Promise.resolve("success");
let P4 = Promise.reject("error");

const result = Promise.race([P, P2, P3, P4]);
console.log(result);  // OK


let P = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("OK");
    }, 100);
});
let P2 = Promise.resolve("success");
let P4 = Promise.reject("error");

const result = Promise.race([P, P2, P3, P4]);
console.log(result); //success

八:Promise的几个关键问题

1. 如何改变promise的状态?

(1):resolve(value):如果当前是pending就会变为resolved;

(2):reject(reason):如果当前是pending就会变为rejected;

(3):抛出异常:如果当前是pending就会变为rejected

let P = new Promise((resolve ,reject)=>{
    // 1.resolve函数
    // resolve('OK') //pending  ===>  resolved (fulfilled)
    // 2.reject函数
    // reject('error')  //pending  ===> rejected
    // 3.抛出异常
    // throw '阿欧,出问题了'
})

2. 一个promise指定多个成功/失败回调函数,都会调用吗?

当promise改变为对应状态时都会调用

3. 改变promise状态【resolve()/reject()】和指定回调函数【then()】谁先谁后?

(1):都有可能,正常情况下是先指定回调再改变状态,但也可以先改变状态再指定回调

(2):如何先改变状态再指定回调?

①:在执行器中直接调用resolve() /reject()===>{同步任务}

②:延迟更长时间才调用then()

(3):什么时候才能得到数据?

①:如果先指定的回调,那当状态发生改变时,回调函数就会调用,得到数据

②:如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据

4. promise.then() 返回新的promise的结果状态有什么决定?

(1):简单表达:有then()指定的回调函数执行的结果决定

(2):详细表达

①:如果抛出异常,新promise变为rejected,reason为抛出的异常

②:如果返回的是非promise的任意值,新promise变为resolved,value为返回值

③:如果返回的是另一个新promise,此promise的结果就会成为新promise的结果

5. promise如何串联多个操作任务?

(1):promise的then()返回一个新的promise,可以看成then()的链式调用

(2):通过then的链式调用串联多个同步/异步任务

let P = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("OK");
    }, 1000);
}).then((value) => {
    return new Promise((resolve, reject) => {
        resolve("success");
    });
}).then((value) => {
        console.log(value); // success
}).then((value) => {
        console.log(value); //undefined
});

6. promise异常穿透?

(1):当使用promise的then链式调用时,可以在最后指定失败的回调

(2):前面任何操作出了异常,都会传到最后失败的回调中处理

let P = new Promise((resolve, reject) => {
    setTimeout(() => {
        reject("error");
    }, 1000);
}) .then((value) => {
    return new Promise((resolve, reject) => {
        resolve("success");
    });
 }) .then((value) => {
    console.log(111);
 }) .then((value) => {
    console.log(222);
 }).catch((reason) => {
    console.warn(reason);  //error
 });

//例子:中间某一个环节错误
let P = new Promise((resolve, reject) => {
    setTimeout(() => {
        resolve("OK");
    }, 1000);
}) .then((value) => {
    return new Promise((resolve, reject) => {
        resolve("success");
    });
 }) .then((value) => {
   throw '失败啦!'
 }) .then((value) => {
    console.log(222);
 }).catch((reason) => {
    console.warn(reason);  //error
 });

7. 中断promise链?

(1):当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数

(2):办法:在回调函数中返回一个pending状态的promise对象

let P = new Promise((resolve, reject) => {
        setTimeout(() => {
          resolve("OK");
        }, 1000);
      })
        .then((value) => {
          console.log(111);
          // 有且只有一个方式
          return new Promise(() => {});
        })
        .then((value) => {
          console.log(222);
        })
        .then((value) => {
          console.log(333);
        })
        .catch((reason) => {
          console.warn(reason); //error
        });
//最后控制台打印结果为:111



版权声明:本文为weixin_54685571原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。