• promise相关知识,看看你都会了吗


    promise相关知识

    觉得promise没问题的可以直接挑战最后的测试题哦

    什么是promise,为什么要使用promise

    Promise是JS中进行异步编程的新解决方案;promise对象用来封装一个异步操作并可以获取其成功或失败的结果

    优劣势

    优点:

    原来处理异步是纯回调,相比原来的优势:原来处理异步编程,在为执行异步的时候就需要指定回调函数;而promise可以在异步执行完再指定回调

    1. 指定回调函数的方式更加灵活: 可以在请求发出甚至结束后指定回调函数

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

    原始纯回调:

    var fs = require("fs");
    fs.readFile("./src/a.txt", "utf-8", function (err, data) {
      if (err) {
        throw err;
      }
      console.log(data);
      fs.readFile("./src/b.txt", "utf-8", function (err, data) {
        if (err) {
          throw err;
        }
        console.log(data);
        fs.readFile("./src/c.txt", "utf-8", function (err, data) {
          if (err) {
            throw err;
          }
          console.log(data);
        });
      });
    });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    promise的写法:

     new Promise(function (resolve, reject) {
      fs.readFile("./src/a.txt", "utf-8", function (err, data) {
        if (err) {
          reject(err);
        }
        console.log(data);
        resolve();
      });
    })
      .then(() => {
        fs.readFile("./src/b.txt", "utf-8", function (err, data) {
          if (err) {
            throw err;
          }
          console.log(data);
        });
      })
      .then(() => {
        fs.readFile("./src/c.txt", "utf-8", function (err, data) {
          if (err) {
            throw err;
          }
          console.log(data);
        });
      })
      .catch((err) => {
        console.log(err);
      });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    缺点:

    一旦新建就会立即执行,中途无法取消

    如果不设置回调函数,则内部抛出的错误不会反应到外部

    处于pending状态时,无法知道目前进展到哪一阶段

    promise的状态

    三种状态

    pending :未确定的,起始状态

    resolved (fulfilled) :成功的,调用了resolve()后的状态

    rejected :失败的,调用了reject()后的状态

    状态改变

    pending=>resolved

    pending=>rejected

    特点:

    1>对象的状态不受外界影响,只有异步任务的结果可以决定当前的状态

    2>一旦状态发生改变,就不会再次变了

    修改promise状态的三种方法

    1》调用resolve方法

    2》调用reject方法

    3》抛出异常 throw

          const p = new Promise((resolve, reject) => {
            // 1》调用resolve, pending --> resolved
            // resolve(1); // resolved 1
            // 2》调用reject, pending --> rejected
            // reject(2); // rejected 2
            // 3》抛出异常, pending --> rejected
            throw 3; // rejected 3
          });
          p.then(
            (value) => console.log("resolved", value),
            (reason) => console.log("rejected", reason)
          );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    throw和reject() 都可以将promise状态变为rejected状态,但是throw抛出异常后,后面的代码是不会执行了的;这里是和throw的正常使用是一样,这里抛出的错误,.catch是能够捕获到的

    基本使用

    new Promise()

    new Promise()接收一个执行器函数,这个函数是一个立即执行的回调函数,执行器函数中接收两个方法,reject和resolve方法,它们是修改promise的状态的;如果调用其中一个,就会修改promise状态,,promise状态修改,就会调用对应的then或catch中的onResolved,onRejected回调函数

          // 1 构造一个poromise实例对象
          const p = new Promise((resolve, reject) => {
            // 同步的执行器函数
            // 2执行异步任务
            setTimeout(() => {
              // 3.1如果异步操作成功,promise的状态变为resolved,执行resolve函数
              if (Math.random() > 0.5) {
                resolve(11111);
              } else {
                // 3.2如果异步操作失败,promise的状态变为rejected,执行reject函数
                reject(22222);
              }
            }, 0);
          });
          // 4 通过then或catch拿到结果
          p.then((val) => console.log(val)).catch((reason) => console.log(reason));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    大概的执行过程:

    1》创建promise对象(pending),指定执行器函数,执行器函数是一个立即执行的同步任务

    2》在执行器函数中启动异步任务

    3》根据异步结果做不同处理:如果成功,调用resolve(),指定成功的value,promise状态变为resolved; 如果失败,调用reject()函数,指定失败的reason,promise状态变为rejected

    4》指定成功或失败的回调函数来获取成功的value或失败的reason

    then中可以接收两个回调,一个成功,一个失败,但是我们一般不这么写

    执行器函数是一个同步任务,.then和catch中的回调函数是一个异步任务(微任务)

    简单地使用promise包装ajax请求

          function getAsyncRequest(url) {
            return new Promise((resolve, reject) => {
              const xhr = new XMLHttpRequest();
              xhr.open("GET", url);
              xhr.onload = () => JSON.parse(resolve(xhr.responseText));
              xhr.onerror = () => JSON.parse(reject(xhr.statusText));
              xhr.send();
            });
          }
          getAsyncRequest("https://www.testapi.com").then((res) =>
            console.log(res)
          ).catch((error) => console.log(error));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

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

    不一定,都有可能;正常情况是先指定回调,再改状态;但是也有可能是先改状态,再指定回调;

    指定回调是 .then或 .catch ;改变状态是调用resolve,reject或抛出异常

    1》先指定回调,后改状态

          const p = new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve(1);
            });
          }).then((value) => console.log(value));
    
    • 1
    • 2
    • 3
    • 4
    • 5

    2》先改状态,后指定回调

          const p = new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve(1);
            });
          });
          setTimeout(() => {
            p.then((value) => console.log(value));
          }, 2000);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
          const p = new Promise((resolve, reject) => {
              resolve(1);
          }).then((value) => console.log(value));
    
    • 1
    • 2
    • 3
    Promise.prototype.then()

    作用:为promise实例添加状态改变时的回调函数

    返回值:返回一个新的Promise对象,因此可以使用链式写法

    基本语法使用

          new Promise((resolve, reject) => {
            setTimeout(() => {
              reject(1);
            });
          }).then(
            (value) => console.log(value),
            (reason) => console.log(reason)
          );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    参数:接收两个回调函数作为参数,第一个是变为resolved状态的回调,第二个是变为rejected状态的回调;一般我们只是用第一个参数,另一个回调写在catch中

    then中返回的promise:上一个回调函数完成后,将返回结果作为参数传入下一个回到函数

    1》如果上一个函数返回一个正常值:将执行成功的回调,拿到的值就是上一个函数的返回值

    2》如果上一个函数返回一个promise:

    返回resolved状态的promise — 执行成功的回调onResolved()

    返回rejected状态的promise — 执行失败的回调onRejected()

    3》如果上一个函数抛出异常:执行 失败的回到onRejected()

          const p = new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve(1);
            });
          })
            p.then((value) => {
              console.log("resolve1", value); // resolve1 1
              return value; // 返回一个resolved状态的promise对象,结果为1
            })
            .then((val) => console.log("resolve2", val)) // resolve2 1;返回resolved状态promise
            .then((v) => {
              console.log("resolve3", v); // resolve3 undefined
              return Promise.resolve(3); // 返回一个resolved状态的promise对象,结果为3
            })
            .then((value) => {
              console.log("resolve4", value); // resolve3 3
              return Promise.reject(4);// 返回一个rejected状态的promise对象,结果为4
            })
            .catch((reason) => {
              console.log("reject4", reason); // reject4 4
              throw 5; // 抛出异常,返回了一个rejected状态的promise,结果为5
            })
            .then((v) => {console.log(v)})
            .catch((err) => console.log("reject5", 5)); // reject5 5
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

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

    由执行函数中的异步任务执行结果决定

    1)如果抛出异常,新promise变为rejected ;reason为抛出异常(抛出什么,后面then中reason就等于什么)
    2)如果返回的是非promise的任意值,新promise变为resolved,value为返回的值(后面then中value为return出来的值)
    3)如果返回的是另一个新的promise,此promise的结果就为新promise的结果

    如何中断promise链

    返回一个pending状态的promise

          new Promise((resolve, reject) => {
            setTimeout(() => {
              resolve(1);
            });
          })
            .then((value) => {
              console.log("resolve1", value); // resolve1 1
              return new Promise(() => {
                console.log("我没有调用resolve和reject函数,状态一直时pending");
              });
            })
            .then((val) => console.log("resolve2", val)) // 不会打印
            .catch((err) => console.log("reject5", 5)); // 不会打印
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    因为then中返回了一个promise对象,他的执行器函数为一个空的对象,既没有调用resolve()函数,也没有调用reject()函数,返回的时一个pending状态的promise实例对象,所以不会继续执行后面的then或catch中回调函数

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

    成功就调用所有成功的回调,失败就调用所有失败的回调,只是成功和失败的回调同时都调用:

      const p = new Promise((resolve, reject) => {
        resolve(1);
      });
      p.then(
        (value) => console.log("resolved1", value),
        (reason) => console.log("rejected1", reason)
      );
      p.then(
        (value) => console.log("resolved2", value),
        (reason) => console.log("rejected2", reason)
      );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    Promise.prototype.catch()

    作用:指定发生错误是的回调,

    返回值:返回一个新Promise对象

    相当于

    .then(null,onRejected)
    
    • 1

    promise状态变为rejected就会执行catch中的回调,另外then中抛出错误也会被catch捕获

    如果Promise状态已经发生改变,再抛出错误是无效的,改变promise状态的reject()的作用等同于抛出异常

    如果没有使用catch方法指定错误处理的回调,Promise对象抛出的错误不会传递到外层的代码,即不会由任何反应

    promise错误穿透

    为什么catch中的回调在最后还会执行呢?

    如果then只指定了resolved状态的回调,相当于另一个采用默认的抛出异常,异常值为前面promise的结果;因为抛出异常,then会返一个失败的promise,后面的回调同样的,到最后catch前的还是一样,catch中的回调最终就会执行

          new Promise((resolve, reject) => {
            setTimeout(() => {
              reject(1);
            });
          })
            .then(
              (value) => console.log(value)
              //   (reason) => {
              //     throw reason;
              //     return Promise.reject(reason);
              //   }
            )
            .then((value) => console.log(value))
            .catch((err) => console.log(err));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    Promise.resolve()

    参数如果不是一个对象,或不是具有then方法的对象,返回一个resolved状态的的Promise对象

          const p1 = Promise.resolve(222);
    // 等同于
          const p2 = new Promise((resolve, reject) => {
            resolve(222);
          });
    
    • 1
    • 2
    • 3
    • 4
    • 5

    如果参数是一个Promise实例,那么Promise.resolve()不做任何处理,原封不动返回实例

          const p2 = new Promise((resolve, reject) => {
            resolve(222);
          });
          const p1 = Promise.resolve(p2); // 有一点像 p1= p2
    
    • 1
    • 2
    • 3
    • 4

    如果参数是一个具有then方法的对象,会先就对象变为promise对象,然后立即执行then方法

    Promise.reject()

    返回一个rejected状态的promise对象,和resolve类似

    Promise.all()

    将多个Promsie包装成一个新的Promise实例

    const p = Promise.all([p1,p2,p3])
    
    • 1

    1> 只有当p1 p2 p3状态都变为resolved,p的状态才会变为resolved,此时p1 p2 p3 返回值组成一个数组,传递给p的回调函数

    2> 只要当p1 p2 p3中有一个变为rejected,p的状态就会变为rejected,此时第一个被rejected的实例的返回值传递给p的回调函数

    如果作为参数的Promise实例自身定义了catch方法,那么他被rejected时并不会触发Promise.all或race的catch方法

      //   如果p3,P4都有catch,那么不会走到Promise.all中的catch,如果没有catch,但是状态又是rejected,就会走到catch中,而且只有最先执行完的那个失败的值
      const p3 = new Promise((resolve, reject) => {
        // resolve(3);
        resolve(3);
      })
        .then((val) => val)
        .catch((reason) => reason);
      const p4 = new Promise((resolve, reject) => {
        //   resolve(4)
        reject(4);
      })
        .then((val) => val)
        .catch((reason) => reason);
      Promise.all([p3, p4])
        .then((val) => console.log(val))
        .catch((reason) => console.log(reason));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    最后一个catch是Promise.all()包装生成的Promise对象的onRejected回调

    Promise.race()
    const p = Promise.race([p1,p2,p3])
    
    • 1

    只要 p1 p2 p3 中一个状态发生改变,p 的状态就跟着发生改变,最先变的Promise实例的返回值会传递给p的回调函数

    Promise.prototype.done()

    不管是then还是catch方法结尾,最后一个地方抛出的错误都无法捕捉到,因为Promise内部的错误不会冒泡到全局

    捕捉任何可能出现的错误,并向全局抛出

          try {
            new Promise((resolve, reject) => {
              reject(1);
            })
              .catch((reason) => {
                console.log(errTest); //ReferenceError: errTest is not defined
              })
              .done();
          } catch (err) {
            console.log("捕获到错误"); //捕获到错误
          }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    Promise.prototype.finally()

    接收一个普通函数,无论如何都会执行,和 try … catch 中的finally差不多

          new Promise((resolve, reject) => {
            resolve(2);
          })
            .then((value) => {
              throw 3;
            })
            .finally(function () {
              console.log("all is over"); // 会打印 all is over
            });
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    promise的错误捕获问题

    捕获不到的原因:try…catch只能捕获到同步错误

    • 使用Promise的catch方法内部消化;
    • 使用async和await将异步错误转同步错误再由try catch捕获

    最后的小测试

    最后的打印结果是?

    请耐心一点,本文精华都浓缩在这道题中了

          const p = new Promise((resolve, reject) => {
            console.log(1);
            setTimeout(() => {
              resolve(2);
              console.log(3);
            }, 0);
          });
    
          console.log(4);
    
          p.then((value) => {
            console.log(value);
          })
            .then(() => {
              return new Promise((resolve, reject) => {
                throw 5;
                console.log(6);
              });
            })
            .then((value) => {
              console.log(value);
            })
            .catch((reason) => console.log(reason))
            .then((val) => console.log(val))
            .then(() => {
              return new Promise((resolve, reject) => {
                resolve(8);
                console.log(9);
                reject(10);
              }).then(
                (value) => {
                  console.log(value);
                },
                (reason) => {
                  console.log(reason);
                }
              );
            });
    
          p.then((val) => {
            console.log(val);
          })
            .then((v) => {
              return new Promise(() => {});
            })
            .then((value) => {
              console.log(11);
            })
            .catch((err) => console.log(err));
    
          Promise.reject(7).catch((reason) => console.log(reason));
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51

    你的答案是什么呢?

  • 相关阅读:
    继(VScode上传到git仓库详细教程)后,创建新仓库以及上传新代码到git仓库教程
    Flink 背压详解及调优处理
    系统架构设计师(第二版)学习笔记----需求工程
    Emmet详解
    Hbuilder本地调试微信H5项目(一)
    【笔记】ASP.NET Core 2.2 Web API —— 学习笔记
    前端工作小结33-确定需求报告
    同态加密库Seal库的安装(win11+VS2022)
    Win10远程连接服务器失败,报错:出现了内部错误
    ubuntu18.04出现关于显卡驱动问题的解决办法
  • 原文地址:https://blog.csdn.net/weixin_50576800/article/details/126800419