新手咋地

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

Promise

Promise介绍与基本使用

理解

1.抽象表达

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

  2. Promise是JS中进行异步编程的新解决方案

     

    备注:旧方案是单纯使用回调函数

2.具体表达

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

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

为什么要用Promise?

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

    1. 旧的:必须在启动异步任务前指定

    1. promise:启动异步任务=>返回promie对象=→>给promise对象绑定回调函数(甚至可以在异步任务结束后指定/多个)

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

    1.什么是回调地狱? 回调函数嵌套调用,外部回调函数异步执行的结果是嵌 套的回调执行的条件

    2.回调地狱的缺点? 不便于阅读不便于异常处理

    3.解决方案? promise链式调用

    4.终极解决方案?

抽奖

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
</head>

<body>
   <button id="btn" value="">抽奖</button>

   <script>
       function rand(m, n) {
           return Math.ceil(Math.random() * (n - m + 1) + m - 1);
      }
       const btn = document.getElementById("btn");

       //Promise
       // resolve 解决 函数类型的数据
       // reject 拒绝 函数类型的数据
       btn.addEventListener('click', function () {

           //定时器
           //
           // btn.addEventListener('click', function () {
           //     setTimeout(() => {
           //         let n = rand(1, 100);
           //         if (n <= 30) {
           //             alert('恭喜你中奖了!');
           //         } else {
           //             alert('下次再来')
           //         }
           //     }, 1000)
           // })

           const p = new Promise((resolve, reject) => {

               setTimeout(() => {
                   let n = rand(1, 100);
                   if (n <= 30) {
                       resolve(n);//将promise对象的状态设置为成功
                  } else {
                       reject(n);//将promise对象的状态设置为失败
                  }
              }, 1000)

          })
           // 调用then方法
           //value值
           //reason 理由
           p.then((value) => {
               alert("恭喜你中奖了" + value);
          }, (reason) => {
               alert("下次再来" + reason);
          })
      })
   </script>
</body>

</html>

运行结果

image-20211121104819558

image-20211121105702437

 

 

fs模块

const fs = require('fs');
// fs.readFile('./resource/resource.txt', (err, data) => {
//     //如果出错,则抛出错误
//     if (err) throw err;
//     //输出文件内容

//     console.log(data.toString());
// })

//Promise
let p = new Promise((resolve, reject) => {
   fs.readFile('./resource/resource.txt', (err, data) => {
       //如果出错,则抛出错误
       if (err) reject(err);
       //输出文件内容

       resolve(data);
  });

});
p.then((value) => {
   console.log(value.toString());
}, (reason) => {
   console.log(reason)
})

ajax

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
</head>

<body>
   <button id="btn">请求ajax</button>
   <script>
       const btn = document.getElementById("btn");
       btn.addEventListener("click", function () {
           // const xhr = new XMLHttpRequest();
           // xhr.open('GET', 'https://api.apiopen.top/getJoke')
           // xhr.send();
           // xhr.onreadystatechange = function () {
           //     if (xhr.readyState === 4) {
           //         //判断响应状态码2xx
           //         if (xhr.status >= 200 && xhr.status < 300) {
           //             //控制台输出响应体
           //             console.log(xhr.response);
           //         } else {
           //             console.log(xhr.status)
           //         }
           //     }
           // }
           //Promise
           const p = new Promise((resolve, reject) => {
               const xhr = new XMLHttpRequest();
               xhr.open('GET', 'https://api.apiopen.top/getJoke')
               xhr.send();

               xhr.onreadystatechange = function () {
                   if (xhr.readyState === 4) {
                       //判断响应状态码2xx
                       if (xhr.status >= 200 && xhr.status < 300) {
                           //控制台输出响应体
                           resolve(xhr.response);
                      } else {
                           reject(xhr.status)
                      }
                  }
              }
          })
           p.then(value => {
               console.log(value)
          }), reason => {
               console.warn(reason)
          }
      })
   </script>
</body>

</html>

封装fs模块

// 封装一个函数 mineReadFile读取文件内容
// 参数:path 文件路径
// 返回:promise对象
function mineReadFile(path) {
   return new Promise((resolve, reject) => {
       require('fs').readFile(path, (err, data) => {
           if (err) reject(err);//成功
           resolve(data);
      })
  });
}
mineReadFile('./resource/resource.txt').then(value => {
   console.log(value.toString());
}, reason => {
   console.log(reason);
});

util.promisify方法

// util.promisify方法
//引入utilmokuai
const util = require('util');
//引入fs模块
const fs = require('fs')

//返回一个新的函数
let mineReadFile = util.promisify(fs.readFile);

mineReadFile('./resource/resource.txt').then(value => {
   console.log(value.toString())
})

sendAjax

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
</head>

<body>
   <script>
       function sendAjax(url) {
           return new Promise((resolve, reject) => {
               const xhr = new XMLHttpRequest();
               xhr.open('GET', url)
               xhr.send();

               xhr.onreadystatechange = function () {
                   if (xhr.readyState === 4) {
                       //判断响应状态码2xx
                       if (xhr.status >= 200 && xhr.status < 300) {
                           //控制台输出响应体
                           resolve(xhr.response);
                      } else {
                           reject(xhr.status)
                      }
                  }
              }
          })
      }
       sendAjax('https://api.apiopen.top/getJoke').then(value => {
           console.log(value)
      }, reason => { console.warn(reason) })
   </script>
</body>

</html>

promise的状态改变

  1. pending变为resolved

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

    实例对象中的一个属性PromiseState

    pending 未决定的

    resolve/fullfilled 成功

    rejected 失败

    Promise对象的值

    实例对象中的另一个属性 PromiseResult

    保存着异步任务对象[成功/失败]的结果

    只有resolve/reject可以修改

promise的工作流程

image-20211121135636743

如何使用Promise

API

  1. Promise构造函数:Promise (excutor){} (1) executor函数:执行器(resolve, reject)=>{}

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

    (3) reject函数:内部定义失败时我们调用的函数reason =>{} 说明: executor 会在 Promise 内部立即同步调用,异步操作在执行器中执行,也就是这个函数不会进入到队列当中去

  2. Promise.prototype.then方法:(onResolved, onRejected) =>{}(1)onResolved,函数:成功的回调函数(value)=>{} (2)onRejected函数:失败的回调函数(reason) =>{} 说明:指定用于得到成功value的成功回调和用于得到失败reason的失败回调返回一个新的promise对象

  3. Promise.prototype.catch方法: (onRejected) => {} (1) onRejected函数:失败的回调函数(reason) => {}

  4. Promise.resolve方法: (value)=> {} (1) value: 成功的数据或promise对象 说明:返回一个成功/失败的promise对象

    <!DOCTYPE html>
    <html lang="en">

    <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>Document</title>
    </head>

    <body>

       <script>
           // 如果传入的参数为非Promise类型的对象,则返回的结果为成功的promise对象
           // 如果传入的参数为Promise对象,则参数的结果决定了resolve的结果
           let p1 = Promise.resolve(123);
           console.log(p1);
           let p2 = Promise.resolve(new Promise((resolve, reject) => {
               reject();
          }))
           console.log(p2)
       </script>
    </body>

    </html>

     

  5. Promise.reject方法: (reason) => {} (1) reason: 失败的原因. 说明:返回一个失败的promise对象

    <!DOCTYPE html>
    <html lang="en">

    <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>Document</title>
    </head>

    <body>
       <script>
           //返回的结果永远是失败的promise对象
           let p = Promise.reject(1);
           console.log(p);
           let p1 = Promise.reject("iloveyou");
           console.log(p1);
           let p2 = Promise.reject(new Promise((resolve, reject) => {
               resolve('ok');
          }))
           console.log(p2);
       </script>
    </body>

    </html>

     

  6. Promise.all方法: (promises)=> {} (1) promises: 包含n个promise的数组 说明:返回一个新的promise,只有所有的promise都成功才成功,只要有一-个失败了就直接失败

      <!DOCTYPE html>
    <html lang="en">

    <head>
       <meta charset="UTF-8">
       <meta http-equiv="X-UA-Compatible" content="IE=edge">
       <meta name="viewport" content="width=device-width, initial-scale=1.0">
       <title>Document</title>
    </head>

    <body>
       <script>
           let p1 = new Promise((resolve, reject) => {
               resolve('ok');
          })
           let p2 = Promise.resolve('success');
           let p3 = Promise.resolve('oh,yeah');
           const result = Promise.all([p1, p2, p3])
           console.log(result)

           let p4 = Promise.reject('error');
           const result2 = Promise.all([p1, p2, p4])
           console.log(result2)

       </script>
    </body>

    </html>

    image-20211121142430895

  7. Promise.race 方法: (promises)=> {} : (1) promises: 包含n个promise的数组 说明:返回一个新的promise,第一个完成的promise的结果状态就是最终的结果状态

<!DOCTYPE html>
<html lang="en">

<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Document</title>
</head>

<body>
   <script>
       let p1 = new Promise((resolve, reject) => {
           setTimeout(() => {
               resolve('ok');
          }, 1000)
      })
       let p2 = Promise.reject('error');
       let p3 = Promise.resolve('oh,yeah');
       const result = Promise.race([p1, p2, p3])
       console.log(result)

   </script>
</body>

</html>

image-20211121143019317

promise的几个关键问题

  1. 如何改变promise的状态? (1) resolve(value): 如果当前是pending就会变为resolved (2) reject(reason): 如果当前是pending就会变为rejected (3) 抛出异常:如果当前是pending就会变为rejected throw ’出错啦!‘

  2. 一个promise指定多个成功/失败回调函数,都会调用吗? 当promise改变为对应状态时都会调用

  3. 改变promise状态和指定回调函数谁先谁后? (1)都有可能,正常情况下是先指定回调再改变状态,但也可以先改状态再指定回调 (2)如何 先改状态再指定回调? ①在执行 器中直接调用resolve()/reject() ②延迟更长时间才调用then() (3)什么时候才能得到数据?

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

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

  4. promise.then()返回的新promise的结果状态由什么决定? (1)简单表达: 由then()指定的回调函数执行的结果决定 (2)详细表达: ①如果抛出异常, 新promise变为rejected, reason为抛出的异常 ②如果返 回的是非promise的任意值,新promise变为resolved, value为返回的值 ③如果返 回的是另-一个新promise,此promise的结果就会成为新promise的结果

posted on 2021-11-21 14:57  新手咋地  阅读(178)  评论(0)    收藏  举报