Promise理解+ JS 的执行机制

做一道题,理解一下:

function getPrinterList() {
  let res = '初始'
  setTimeout(() => {
    res = 1
  },1000)
  return res
}

let res = getPrinterList()
console.log(res); //输出'初始'

在getPrinterList函数中,先分清同步异步.

JS执行语句时,会区分同步异步,把所有的同步放在同步队列中,把所有的异步放到异步队列中; 等所有的同步任务执行完,再执行异步任务. 所以输出的res是'初始'.

如果我们想让getPrinterList函数输出为 1, 那么该怎么办呢?

只需将getPrinterList函数返回一个promise即可,代码见下:

function getPrinterList() {
    return new Promise((resolve,reject) => {
         let res = '初始'
         setTimeout(() => {
            res = 1
            resolve(res)
          },1000)
    })
}
(1)---getPrinterList().then(res => {console.log(res)}) //输出的res为1
此处和我们经常使用封装好的request请求是一样的.

(2)
    关于(1)也可以写为:
    async func(){
      const res = await getPrinterList()
      console.log(res) //输出的res为1
    }

注意:resolve(res)抛出结果的位置,是在setTimeout()里面; 

function getPrinterList() {
    return new Promise((resolve,reject) => {
         let res = '初始' //同步
         setTimeout(() => { //异步
            res = 1
          },1000)
          resolve(res) //同步
    })
}
getPrinterList().then(res => {console.log(res)}) //输出为'初始'

如果resolve(res)放在setTimeout外面,那么输出的res就不是1,而是'初始'了.

可见: 将getPrinterList函数内返回一个Promise,就可以实现我们想要的效果.

类似的,平时我们使用封装好的request,返回的就是promise. 写法有2种:

①先封装好接口函数:

 ②使用接口函数发送请求:

    发送请求写法(1),使用.then

 发送请求写法(2),使用async await 语法糖

async getTableData(){
    const res = await registrationGetRegistRequestPage(请求参数)
    res就是请求的结果
    // const res = await registrationGetRegistRequestPage(请求参数).finally(() => {})
    //使用await时,也可直接调用finally()即无论请求结果成功与否,都要执行的语句
}

关于Promise, 学习可参考: ES6---promise详解及用法_es6 promise的用法_Cirrod的博客-CSDN博客

Promise是一个容器,是一个对象或者说是构造函数,用来封装异步操作并可以获取其成功或失败的结果. 

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

        resolve()可抛出成功结果res即resolve(res);  也可不抛resolve() ----> 抛出成功状态

        reject()可抛出失败结果error即reject(error);  也可不抛reject() ----> 抛出成功状态

})         

service.then()是promise实例的方法,成功时调用

service.catch()是promise实例的方法,失败时调用

service.finnaly()是promise实例的方法,无论成功失败都会调用

 

而async  await是promise的语法糖, 用来处理promise结果.可代替.then () 

使用 async 定义的函数,当它被调用时,它返回的其实是一个 Promise 对象。(当这个 async 函数返回一个值时,Promise 的 resolve 方法会负责传递这个值;当 async 函数抛出异常时,Promise 的 reject 方法也会传递这个异常值。)

需求: 打印报告成功后, 记录打印次数并且刷新列表.代码如下:

原写法: 

// 点击打印按钮
    async printSingleReport({ row }) {
      // 获取pdf文件流
      let arrayBuffer = await docReportGainReportPdf({
        registrationFormSoid: row.registrationFormSoid,
        requestSoid: row.requestSoid,
        operatorSoid: row.operatorSoid,
      });

      let bob = new Blob([arrayBuffer]);
      // 文件大小太小说明没有获取的pdf流
      if (bob.size < 20) {
        this.$message({
          message: `报告未出!`,
          type: "warning",
        });
      } else {
        this.node2Print(bob, row);
        this.recordPrint(row);
      }
    },
// 记录打印报告次数
    async recordPrint(row) {
      // 不需要返回
      await saveReportPrintRecord({
        registrationFormSoid: row.registrationFormSoid,
        requestSoid: row.requestSoid,
        operatorSoid: row.operatorSoid,
      });
    },
// blob用于传给node接口打印pdf,row用于后续记录打印次数入参所用
    async node2Print(blob, row) {
      const formData = new FormData();
      formData.append("file", blob);
      formData.append("fileType", "pdf");
      formData.append(
        "printName",
        this.$parent.printReportDevice.printDeviceName
      );
      formData.append("type", "server");
      printPDFCustom(formData).then(
        (res) => {
          if (res.code === 200) {
            this.$message.success("打印成功");
          }
          this.$parent.initTableNeedInfo(); //打印报告成功后,刷新列表
        },
        (error) => {
          console.log(error);
        }
      );
    },

原写法解析: 很有可能会出现一个问题: 

现写法: 将打印方法内部返回promise, 再走记录打印次数方法和刷新列表

// 点击打印按钮
    async printSingleReport({ row }) {
      // 获取pdf文件流
      let arrayBuffer = await docReportGainReportPdf({
        registrationFormSoid: row.registrationFormSoid,
        requestSoid: row.requestSoid,
        operatorSoid: row.operatorSoid,
      });

      let bob = new Blob([arrayBuffer]);
      // 文件大小太小说明没有获取的pdf流
      if (bob.size < 20) {
        this.$message({
          message: `报告未出!`,
          type: "warning",
        });
      } else {
        this.node2Print(bob).then((res) => {
          if (res.code === 200) {
            this.$message.success("打印成功");
            this.recordPrint(row); //记录打印次数
            this.$parent.initTableNeedInfo(); //打印报告成功后,刷新列表
          }
        });
      }
    },
    // 记录打印报告次数
    async recordPrint(row) {
      // 不需要返回
      await saveReportPrintRecord({
        registrationFormSoid: row.registrationFormSoid,
        requestSoid: row.requestSoid,
        operatorSoid: row.operatorSoid,
      });
    },
    // node打印-返回promise
    node2Print(blob) {
      return new Promise((resolve, reject) => {
        const formData = new FormData();
        formData.append("file", blob);
        formData.append("fileType", "pdf");
        formData.append(
          "printName",
          this.$parent.printReportDevice.printDeviceName
        );
        formData.append("type", "server");
        printPDFCustom(formData).then(
          (res) => {
            resolve(res);
          },
          (error) => {
            reject(error);
          }
        );
      });
    },

现写法解析:打印方法内部返回promise写法 , 拿到结果再做其他操作,这样不会出现异步的情况

 

 

如果不用.then 可以使用await

或者node2Print方法内部不用返回promise, 更简单的写法,, 直接以下写法更简单粗暴:

实际使用2:

需求:在父组件触发dispatch请求的数据,存储在vuex中时。子组件需要用到这个数据时,有可能会出现获取不到的问题。

解决思路:在dispatch成功后再触发子组件的方法操作。

先看下全局异步请求,返回的是promise才可以:

 从上看到getSelecteds被触发后会返回promise, 那么我们在父组件中dispatch后调用.then方法即可。 

 

JS的执行机制,会区分同步任务和异步任务. 先执行同步任务 再执行异步任务

而异步任务又分为: 宏任务 微任务. (先执行微任务,再执行宏任务)

所以执行顺序可以概括为: 同步任务  微任务  宏任务

常见的同步任务: console;  new Promsie;  resolve() ;  while(true){....} ; fun() 函数调用

常见的宏任务任务: setTimeout;  setInterval; 

常见的微任务: process.nextTick; promise.then();  跟在await右边的代码

注意: 先将所有的同步任务 宏任务 微任务分开; 

先执行同步任务; 再检查微任务队列是否有任务有则执行; 再执行宏任务. 

若有多个宏任务,当当前宏任务中又有微任务,那么将微任务放到微任务队列中. 当执行完该宏任务内的同步任务后,再去执行微任务队列中的微任务.执行完毕之后, 这个循环才算结束.  这个时候再去执行下一个宏任务. 

例题1参考:  js的执行机制_js执行机制_山上有晚星的博客-CSDN博客

例题2:async、await、promise、setTimeout关于宏任务和微任务_async是宏任务还是微任务_周公子よ的博客-CSDN博客

       async function async1() {
            console.log("async1 start");
            await  async2();
            console.log("async1 end");

          }
          async  function async2() {
            console.log( 'async2');
          }
          console.log("script start");
          setTimeout(function () {
            console.log("settimeout");
          },0);
          async1();
          new Promise(function (resolve) {
            console.log("promise1");
            resolve();
          }).then(function () {
            console.log("promise2");
          });
          console.log('script end');

// script start;  async1 start; async2;  promise1; script end; async1 end; promise2; settimeout

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值