异步操作是 Javascript 编程的麻烦事,麻烦到一直有人提出各种各样的方案,试图来解决这个问题,从最早的回调函数,到Promise,到 ES7 的asyncawait,每次都有改进,但又让人觉得不彻底,他们都有额外的复杂性,都需要理解抽象底层运行机制.

ES7 引入的 async/await 是 Javascript 异步编程的一个重大改进.提供了在不阻塞主线程的情况下使用同步代码异步访问资源的能力,async可以让一个方法变成异步,await必须用在爱上一年从内部,下面结合自己实际项目中遇到的问题,和自己对它的一些理解,将从不同的实例说明 async/await 的用法:

async/await 的好处

async/await 给我们带来的重要好处是同步编程风格.看下下面的例子:

// async/await
async getBooksByAuthorwithAwait(authorId) {

  const books = await bookModel.fetchAll(); //接口获取数据方法

  return books.fillter(b=>{b.authorId === authorId})

}
//Promise

getBooksByAuthorwithAwait(authorId) {
  return bookModel.fetchAll().then(books=>books.fillter(b=>{
      b.authorId === authorId
  }))
}

很显然,async/await 比 Promise 更容易理解,如果忽略掉 await 关键字,代码看起来与其他任意一门同步语言一样.

另外一个好处是 async 关键字,尽管看起来不是很明显,它申明 getBooksByAuthorwithAwait() 函数的返回值的是一个 Promise,因此调用者可以安全的调用

getBooksByAuthorwithAwait().then(...) 或 await getBooksByAuthorwithAwait().比如像下面这样的代码:

getBooksByAuthorWithPromise(authorId) {

  if(!authorId) {
    return null
  }

  return bookModel.fetAll().then(books=>books.fillter(b=>b.authorId === authorId))
}

在上面的代码中,getBooksByAuthorWithPromise 可能返回一个 Promise(正常情况) 或 null(异常情况),在这种情况下,调用者无法安全的调用.then().而如果使用 async 声明,则不会出现这种情况.

async/await 是一种改进,但它不过是一种语法糖,他不会完全改变我们的编程风格.从本质上讲,异步函数仍然是 Promise,在正确的使用异步函数之前,你必须了解 Promise,更糟糕的是,大部分时间需要同时使用 Promise 和异步函数.

虽然 await 可以让你的代码看起来像是同步的,但请记住,它仍然是异步的.

在做公司项目 SAAS 系统的时候,就遇到了相关的问题.编辑 SKU 信息,进行保存的操作.要判断是否有重复的 sku 信息,然后前端进行操作提示.然而自己对基础知识理解的不透彻,导致折腾了好一会儿(基于 Vue+ElemeUI 框架).

先看下实际的页面效果吧,我截了个图,此处表单因为多处使用,分离成了一个 vue 的组件引用.

项目截图:
编辑sku保存

点击保存方法:

//保存sku信息方法(要区分新增保存还是编辑保存操作,新增前端操作数组,编辑保存调后端接口。)
async saveskuinfoData() {
      const sukItemSend = Object.assign({}, this.$refs.skuInfo.skuForm);
      sukItemSend.productId = this.$route.query.productId;
      this.$refs.skuInfo.editproskuRule();
      if (this.$refs.skuInfo.formFlag) {
        //验证表单通过
        // sukItemSend.skuId ===0 表示新增添加sku,不等于0表示编辑sku;
        this.submitskuDisabled = true;

        if (this.isSkuExist(sukItemSend) && sukItemSend.skuId === 0) {
          this.$message({
            message: "请不要重复添加相同SKU信息",
            type: "warning"
          });
          this.submitskuDisabled = false;
          return false;

        } else if (sukItemSend.skuId !== 0 && await this.isValidateIsExist(sukItemSend))  {
          //编辑sku保存情况 ,此处写了await,等待异步this.isValidateIsExist(sukItemSend)方法结果有返回了,在执行下面的代码,如果 saveskuinfoData 方法前不加 async 编辑器会报错
          // this.isValidateIsExist(sukItemSend).then(res=>{
          //     console.log(res)
          // });

          this.$message({
            message: '请不要重复添加相同SKU信息',
            type: "warning"
          });
          this.submitskuDisabled = false;
          return false;

        } else {
          updateSku(sukItemSend).then(response => {
            this.handleEditSkuinfoDialogClose();
            //新增方法修改只取商品详情里面的sku信息列表数据
            this.submitskuDisabled = false;
            this.updateproskuinfo(this.$route.query.productId);
          });
        }
      }
    },

//调接口判断是否有重复的sku,异步方法

async isValidateIsExist(sku) {
      //掉接口返回是否有重复sku方法
      let response =  await validateIsExist({
          id: sku.id,
          numUnit: sku.numUnit,
          packNum: sku.packNum,
          packUnit: sku.packUnit,
          productId: sku.productId,
          sellType: sku.sellType,
          tradeType: sku.tradeType
        })
        if(response.status === 200) {

            if(response.data.code === 1) {
                return true;
            } else {
                return false;
            }
        } else {

          this.$message({
            message: response.data.msg,
            type: "error"
          });

        }

    },

点击编辑操作,基本思路流程图说明:
编辑流程图

或者直接在编辑保存的情况下,调用 判断 sku 是否有重复的方法 (异步),也是一样的.提示信息可以用后端返回的提示语.

saveskuinfoData() {
      const sukItemSend = Object.assign({}, this.$refs.skuInfo.skuForm);
      sukItemSend.productId = this.$route.query.productId;
      this.$refs.skuInfo.editproskuRule();
      if (this.$refs.skuInfo.formFlag) {
        //验证表单通过,sukItemSend.skuId ===0 表示新增添加sku,不等于0表示编辑sku;
        this.submitskuDisabled = true;
        if (this.isSkuExist(sukItemSend) && sukItemSend.skuId === 0) {
          this.$message({
            message: "请不要重复添加相同SKU信息",
            type: "warning"
          });
          this.submitskuDisabled = false;
          return false;

        } else if (sukItemSend.skuId !== 0 )  { //编辑sku保存情况 ,判断是否有重复的

          //直接调用 sku是否有重复的方法 (后端接口异步请求,此处没有用到async/await)
          this.isValidateIsExist(sukItemSend);

        } else {
          updateSku(sukItemSend).then(response => {
            this.handleEditSkuinfoDialogClose();
            //新增方法修改只取商品详情里面的sku信息列表数据
            this.submitskuDisabled = false;
            this.updateproskuinfo(this.$route.query.productId);
          });
        }
      }
    },
    async isValidateIsExist(sku) {
      //掉接口返回是否有重复sku方法
      let response =  await validateIsExist({
          id: sku.id,
          numUnit: sku.numUnit,
          packNum: sku.packNum,
          packUnit: sku.packUnit,
          productId: sku.productId,
          sellType: sku.sellType,
          tradeType: sku.tradeType
        })

        if(response.status === 200) {

            if(response.data.code === 1) { //有重复sku信息提示

                 this.$message({
                  message: response.data.msg,
                  type: "warning"
                });
                this.submitskuDisabled = false;
                return false;


            } else { //没有重复的sku,更新操作

                updateSku(sku).then(response => {
                  this.handleEditSkuinfoDialogClose();
                  //新增方法修改只取商品详情里面的sku信息列表数据
                  this.submitskuDisabled = false;
                  this.updateproskuinfo(this.$route.query.productId);
                });

            }
        } else {

          this.$message({
            message: response.data.msg,
            type: "error"
          });

        }

    },

其他模块引用方法

看了一下项目中,其他小伙伴的模块,都在大量的使用新语法,自己也要多用起来.统一代码风格,向大佬们靠齐.哈哈 😝

项目截图:
其他模块

通过此次问题的总结和归纳,也加深了自己对异步的一个理解,以及它的一个流程.新的东西流行起来,一定有它的优点和好处.所以自己也要不断的学习.

ES7 引入的 async/await 关键字绝对是对 Javascript 异步编程的重大改进.它让代码更易于阅读和调试.然而要正确的使用它们,必须了解 Promise.它们不过是语法糖,本质上仍然是 Promise.