• Promise笔记


    目录

    一 介绍

      入门练习

    二 Promise封装

    (1)Promise封装fs读取文件操作

    (2) Promise封装AJAX请求

    三 Promise实例对象属性介绍

    (1)状态

    (2)对象的值

     四 Promise函数对象的方法

    五 promise的几个关键问题

    七 async函数与await表达式

    一 介绍

    (1)抽象表达:
          1) Promise 是一门]新的技术(ES6规范)
           2) Promise 是JS中进行异步编程的新解决方案(旧方案是单纯使用回调函数)
    (2)具体表达:
       1)从语法上来说: Promise是一个构造函数
        2)从功能上来说:promise对象用来封装-一个异步操作并可以获取其成功/失败的结果值

    优点:

    (1)指定回调函数的方式更加灵活
             旧的: 必须在启动异步任务前指定
             promise: 启动异步任务=>返回promie对象=>给promise对象绑定回调函数(甚至可以在  异步任务结束后指定/多个)
    (2)支持链式调用,可以解决回调地狱问题

    扩展:

    回调地狱定义:回调函数嵌套调用,外部回调函数异步执行的结果是嵌套的回调执行的条件
    回调地狱的缺点:不便于阅读、不便于异常处理 

    (1)Promise构造函数

    Promise(executor){ } 

    其中executor函数为执行器:{resolve,reject)=>{},它会在Promise内部立即同步调用,异步操作在执行器中执行

    1. let p = new Promise((resolve, reject) => {
    2. //同步调用
    3. console . log(111);
    4. });
    5. console. log(222);

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

      入门练习

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>title>
    8. <style>
    9. #btn{
    10. width:50px;
    11. height:50px;
    12. background-color: aqua;
    13. }
    14. style>
    15. head>
    16. <body>
    17. <div class="container">
    18. <h2 class="page-header">Promise 初体验h2>
    19. <button class="btn btn-primary" id="btn">点击抽奖button>
    20. div>
    21. <script>
    22. //生成随机数
    23. function rand(m,n){
    24. return Math.ceil(Math.random()*(n-m+1))+m-1;
    25. }
    26. /**
    27. 点击按钮,1s后显示是否中奖(30%概率中奖)
    28. 若中奖弹出 恭喜恭喜,奖品为10万
    29. 若未中奖弹出 再接再厉
    30. */
    31. const btn=document.querySelector('#btn');
    32. //绑定单击事件
    33. btn.addEventListener('click',function(){
    34. /* //定时器
    35. setTimeout(()=>{
    36. let n=rand(1,100);
    37. if(n<=30){
    38. alert('恭喜恭喜,奖品为10万')
    39. }else{
    40. alert('再接再厉')
    41. }
    42. },1000)*/
    43. //Promise形式实现
    44. // resolve 解决函数类型的数据
    45. // reject 拒绝函数类型的数据
    46. const p = new Promise((resolve, reject) => {
    47. setTimeout(() => {
    48. let n = rand(1, 100);
    49. //判断
    50. if(n <= 30){
    51. resolve(n); //将promise对象的状态设置为「 成功」
    52. }else{
    53. reject(n); //将promise 对象的状态设置为「失败」
    54. }
    55. }, 1000);
    56. });
    57. //调用then 方法
    58. p.then((value) => {
    59. alert('恭喜恭喜,奖品为10万,您的中奖数字为'+value);
    60. },(reason)=>{
    61. alert('再接再厉,您的号码为'+reason);
    62. });
    63. })
    64. script>
    65. body>
    66. html>

    二 Promise封装

    (1)Promise封装fs读取文件操作

    1. /**
    2. 封装一个函数ReadFile读取文件内容
    3. *参数:
    4. path文件路径
    5. 返回:
    6. promise对象
    7. */
    8. function ReadFile(path){
    9. return new Promise((resolve,reject)=>{
    10. //读取文件
    11. require('fs').readFile(path,(err,data)=>{
    12. if(err)reject(err);
    13. resolve(data);
    14. })
    15. })
    16. }
    17. ReadFile('./resource/content.txt')
    18. .then(value=>{
    19. console.log(value.toString());
    20. },reason=>{
    21. console.log(reason);
    22. })

     util.promisify(original)函数

    1. //引入util 模块
    2. const util = require( 'util' );
    3. //引入fs模块
    4. const fs = require('fs');
    5. //util.promisify方法将返回一个新的函数由原来的回调函数风格转化为Promise风格的函数
    6. let ReadFile = util.promisify(fs.readFile);
    7. ReadFile('./resource/ content.txt').then(value=>{
    8. console.log(value.toString());
    9. },reason=>{
    10. console.log(reason)
    11. });

    (2) Promise封装AJAX请求

    1. html>
    2. <html lang="en">
    3. <head>
    4. <meta charset="UTF-8">
    5. <meta http-equiv="X-UA-Compatible" content="IE=edge">
    6. <meta name="viewport" content="width=device-width, initial-scale=1.0">
    7. <title>Promise封装AJAX请求title>
    8. head>
    9. <body>
    10. <script>
    11. /**
    12. 封装一个函数sendAJAX 发送GET AJAX请求
    13. 参数 URL
    14. 返回结果Promise 对象*/
    15. function sendAJAX(url){
    16. return new Promise((resolve,reject)=>{
    17. const xhr=new XMLHttpRequest();
    18. xhr.responseType='json';
    19. xhr.open("GET",url);
    20. xhr.send()
    21. xhr.onreadystatechange=function(){
    22. if(xhr.readyState==4){
    23. if(xhr.status>=200&&xhr.status<300){
    24. resolve(xhr.response);
    25. }else{
    26. reject(xhr.status);
    27. }
    28. }
    29. }
    30. })
    31. }
    32. sendAJAX('http://127.0.0.1:8000/server')
    33. .then(value=>{
    34. console.log(value)
    35. },reason=>{
    36. console.log(reason)
    37. })
    38. script>
    39. body>
    40. html>

     服务器.js

    1. const express=require('express')
    2. const app=express();
    3. app.all('/server',(request,response)=>{
    4. //设置响应头 (此处设置允许跨域)
    5. response.setHeader('Access-Control-Allow-Origin','*');
    6. //响应头
    7. response.setHeader('Access-Control-Allow-Headers','*');
    8. //设置响应体(响应体一定是字符串)
    9. const data={name:'zhangSan'};
    10. //JSON.stringify( {} , [ ] , ""),把数据序列化为json字符串
    11. let str=JSON.stringify(data);
    12. response.send(str);
    13. })
    14. app.listen(8000,()=>{
    15. console.log('服务器已经启动,8000端口监听中')
    16. })

    三 Promise实例对象属性介绍

    (1)状态

    1)Promise 的状态-----实例对象中的一个属性(PromiseState)
    pending  未决定的
    resolved / fullfilled 成功
    rejected   失败

     2)状态改变

    1. pending 变为resolved
    2. pending 变为rejected

    只有这2种,且一个promise对象只能改变一次

    (2)对象的值

    实例对象中的另一个属性「PromiseResult」
    保存着异步任务成功/失败的结果:resolve/reject

     四 Promise函数对象的方法

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

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

    1. let p1 = Promise. resolve(521);
    2. //如果传入的参数为非Promise 类型的对象,则返回的结果为成功promise对象
    3. //如果传入的参数为Promise 对象,则参数的结果决定了resolve 的结果
    4. let p2 = Promise . resolve(new Promise((resolve, reject) => {
    5. // resolve('OK');
    6. reject( ' Error');
    7. }))
    8. // console .1og(p2);
    9. //处理失败的结果
    10. p2.catch(reason => {
    11. console . log(reason);|
    12. })

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

        reason:失败的原因

       无论传入参数为什么, 永远返回一个失败的promise对象

    (3)Promise.all:(promise)=>{}

         promises:包含n个promise的数组

        说明:返回一个新的promise,只有所有的promise都成功才成功,成功的结果是所有成功的结果组成的数组;只要有一个失败了就直接失败,失败的结果是数组中失败的结果

    (4)Promise.race方法:(promises)=>{}

       promises:包含n个promise的数组
      说明:返回一个新的promise,第一个改变的promise的结果状态就是最终的结果状态

    五 promise的几个关键问题

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

      (2)一个promise指定多个成功/失败回调函数(即then方法绑定多个回调),都会调用吗?
          当promise改变为对应状态时都会调用

    (3)改变promise状态和指定回调函数谁先谁后?

       都有可能,当执行器函数中的任务是同步任务时,直接去调用时就是改变promise状态先执行;    当执行器函数中的任务是异步任务时,then方法先执行,改变promise状态后执行。

        如何先改状态再指定回调?
         ①在执行器中直接调用resolve()/reject()
         ②延迟更长时间才调用then()
         什么时候才能得到数据(回调函数什么时候执行)?
        ①如果先指定的回调, 那当状态发生改变时,回调函数就会调用,得到数据
         ②如果先改变的状态,那当指定回调时,回调函数就会调用,得到数据
    (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的链式调用串连多个同步/异步任务

    1. let p = new Promise((resolve, reject) => {
    2. setTimeout(() => {
    3. resolve('OK');
    4. }, 1000);
    5. });
    6. p. then(value => {
    7. return new Promise((resolve, reject) => {
    8. resolve("success" );
    9. });
    10. }).then(value => {
    11. console.1og(value);//success
    12. }). then(value => {
    13. console.log(value);//undefined
    14. })

    (6)promise异常传透?
        1)当使用promise的then链式调用时,可以在最后指定失败的回调,
         2)前面任何操作出了 异常,都会传到最后失败的回调中处理

    1. let p = new Promise((resolve, reject) => {
    2. setTimeout(() => {
    3. resolve('OK');
    4. //reject('Err');
    5. },
    6. 1000);
    7. });
    8. p. then(value => {
    9. // console. log(111);
    10. throw '失败啦!';
    11. }). then(value => {
    12. console . log(222);
    13. }).then(value => {
    14. console . log(333);
    15. }). catch(reason => {
    16. console.warn(reason); //失败啦!
    17. });

    (7)如何中断promise链?

        1)当使用promise的then链式调用时,在中间中断,不再调用后面的回调函数
        2)办法: 在回调函数中返回一个pendding状态的promise对象

    1. let p = new Promise((resolve, reject) => {
    2. setTimeout(() => {
    3. resolve( 'OK' );
    4. }, 1000);
    5. });
    6. p. then(value => {
    7. console.log(111);
    8. //有且只有一个方式
    9. return new Promise(() => {});
    10. }). then(value*=>-{
    11. console.1og(222) ;
    12. }) . then(value => {
    13. console. log(333);
    14. }). catch(reason => {
    15. console.warn( reason);
    16. });

    六 Promise封装

    1. class Promise{
    2. //构造方法
    3. constructor(executor){
    4. //添加属性
    5. this.PromiseState='pending';
    6. this.PromiseResult=null;
    7. this.callbacks=[]
    8. //保存实例对象的this值
    9. const self=this;
    10. //resolve函数
    11. function resolve(data){
    12. //判断状态
    13. if(self.PromiseState!=='pending')return;
    14. //1.修改对象的状态(PromiseState)
    15. self.PromiseState='fulfilled';
    16. //2.设置对象结果值(promiseResult)
    17. self.PromiseResult=data;
    18. setTimeout(()=>{
    19. //调用成功的回调函数
    20. self.callbacks.forEach(item=>{
    21. item.onResolved(data);
    22. })
    23. })
    24. }
    25. //reject函数
    26. function reject(data){
    27. //判断状态
    28. if(self.PromiseState!=='pending')return;
    29. //1. 修改对象的状态( promiseState)
    30. self.PromiseState = 'rejected' ;//
    31. //2. 设置对象结果值( promiseResult)
    32. self.PromiseResult = data;
    33. //调用失败的回调函数
    34. setTimeout(()=>{
    35. self.callbacks.forEach(item=>{
    36. item.onRejected(data);
    37. })
    38. })
    39. }
    40. try{
    41. //同步调用
    42. executor(resolve,reject);
    43. }catch(e){
    44. reject(e);
    45. }
    46. }
    47. //then方法封装
    48. then(onResolved, onRejected){
    49. const self=this
    50. //判断回调函数参数
    51. if(typeof onRejected!=='function'){
    52. onRejected=reason=>{
    53. throw reason;
    54. }
    55. }
    56. if(typeof onResolved!=='function'){
    57. onResolved=value=>value;
    58. }
    59. return new Promise((resolve,reject)=>{
    60. //封装函数
    61. function callback(type){
    62. try{
    63. //获取回调函数的执行结果
    64. let result=type(self.PromiseResult)
    65. //判断
    66. if(result instanceof Promise){
    67. result.then(v=>{
    68. resolve(v)
    69. },r=>{
    70. reject(r)
    71. })
    72. }else{
    73. //结果对象状态为成功
    74. resolve(result)
    75. }
    76. }catch(e){
    77. reject(e)
    78. }
    79. }
    80. //调用回调函数 PromiseState
    81. if(this.PromiseState==='fulfilled'){
    82. setTimeout(()=>{
    83. callback(onResolved)
    84. })
    85. }
    86. if(this.PromiseState==='rejected'){
    87. setTimeout(()=>{
    88. callback(onRejected)
    89. })
    90. }
    91. //判断pending状态
    92. if(this.PromiseState==='pending'){
    93. //保存回调函数
    94. this.callbacks.push({
    95. onResolved:function(){
    96. callback(onResolved)
    97. },
    98. onRejected:function(){
    99. callback(onRejected)
    100. }
    101. });
    102. }
    103. })
    104. }
    105. //catch方法
    106. catch(onRejected){
    107. return this.then(undefined,onRejected)
    108. }
    109. //添加resolve方法
    110. static resolve(value){
    111. return new Promise((resolve,reject)=>{
    112. if(value instanceof Promise){
    113. value.then(v=>{
    114. resolve(v)
    115. },r=>{
    116. reject(r)
    117. })
    118. }else{
    119. //状态设置成功
    120. resolve(value);
    121. }
    122. })
    123. }
    124. //添加reject方法
    125. static reject(value){
    126. return new Promise((resolve,reject)=>{
    127. reject(reason);
    128. })
    129. }
    130. //添加all方法
    131. static all(promises){
    132. let count=0;
    133. let arr=[];
    134. for(let i=0;ilength;i++){
    135. promises[i].then(v=>{
    136. count++;
    137. arr[i]=v;
    138. if(count===promises.length){
    139. resolve(arr)}
    140. },r=>{
    141. reject(r);
    142. })
    143. }
    144. }
    145. //添加race方法
    146. static race(promises){
    147. return new Promise((resolve,reject)=>{
    148. for(let i=0;ilength;i++){
    149. promises[i].then(v=>{
    150. //修改返回对象的状态为成功
    151. resolve(v);
    152. },r=>{
    153. //修改返回对象的状态为失败
    154. reject(r);
    155. })
    156. }
    157. })
    158. }
    159. }

    七 async函数与await表达式

    async函数:async function 函数名(){ }

    函数的返回值为promise对象
    promise对象的结果由async函数执行的返回值决定

     await表达式指定异步执行的任务:

    await右侧的表达式一般为promise对象,但也可以是其它的值
    如果表达式是promise对象, await返回的是promise成功的值
    如果表达式是其它值,直接将此值作为await的返回值

    注意:

    await必须写在async函数中,但async函数中可以没有await
    如果await的promise失败了,就会抛出异常,需要通过t..catch捕获处理
     

    读取文件:

    1. const fs=require('fs')
    2. const util=require('util');
    3. const mineReadFile=util.promisify(fs.readFile)
    4. /*
    5. //回调函数的方式
    6. fs. readFile('../resource/content.txt', (err, data1) => {
    7. if(err) throw err;
    8. fs. readFile('../resource/content2.txt', (err, data2) => {
    9. if(err) throw err;
    10. console.log(data1 + data2 );
    11. });
    12. });
    13. */
    14. //async与await
    15. async function main(){
    16. try{
    17. let data1=await mineReadFile('../resource/content.txt');
    18. let data2=await mineReadFile('../resource/content2.txt');
    19. console.log(data1+data2)
    20. }
    21. catch(e){
    22. console.log(e)
    23. }
    24. }
    25. main();

  • 相关阅读:
    springboot毕设项目瓷砖直销系统g5yc1(java+VUE+Mybatis+Maven+Mysql)
    计算机毕设源码网站springboot毕业设计管理系统
    C++ 基本的输入输出
    git diff 操作
    为了 Vue 组件测试,你需要为每个事件绑定的方法加上括号吗?
    剑指Offer || :栈与队列(简单)
    Python mysql 封装备用
    了解模板模式
    cnn感受野计算方法
    小程序提示没有找到可以构建的NPM包解决方法
  • 原文地址:https://blog.csdn.net/qq_62401904/article/details/126138540