记录一个坑,Vue 在业务驱动学习,不免踩了很多坑,不过这个问题其实并不是仅出现在Vue中,属于 Ajax 的同步/异步问题。虽然我不是前端开发,但也避免不了写 Ajax ,长时间使用Ajax 一直都忽略了一个致命问题,那就是同步问题。大家知道Ajax出现就是为了实现异步请求服务器防止页面卡顿,然而并不是所有的业务都要基于异步执行,或者说有些逻辑必须要同步执行,即执行完某一个后台请求后才能继续执行代码。忽视的问题,就是脚下的坑。。。


问题描述

现在有这样的一个业务,希望在进入页面和页面结束时记录时间戳,首先想到的是在 Js 中 new Date() 对象,但经验告诉我们这样的数据是不安全的,因为浏览器本地的时间是可以人为更改的。我想到的解决办法是向服务器请求一个服务器的系统时间。这样一切都没有问题。

代码实现

.vue 的 Js 代码

<script>
export default {
  name: 'aoligei',
  data () {
    return {
      timeLog: { // 时间戳日志记录对象
        'contNo': this.$route.params.signature.contNo, // 保单号
        'businessType': '微信扫码' // 业务类型
      },
      serverTime: '' // 服务器时间
    }
  },
  created() { // Vue 实例创建时执行的狗子
    // 回调用法,使用回调获取方法的返回值
    this.getServerTime() // 获取服务器系统时间
    this.timeLog.beginDate = this.serverTime
  },
  methods: {
    // 获取服务器系统时间
    getServerTime () {
      var _this = this
      this.axios.get('/getServerSysTime')
        .then(res => {
          _this.serverTime = new Date(res.data)
        })
    }
  },
  beforeDestroy() { // Vue Destory方法执行前的狗子
    // 回调用法,使用回调获取方法的返回值
    var _this = this
    this.getServerTime() // 获取服务器时间
    this.timeLog.endDate = this.serverTime
    var timeLog= _this.timeLog
    if (_this.timeLog.createDate) {
      _this.axios.post('/保存时间戳的接口', {
        timeLog
      })
    }
  }
}
</script>

Java 接口

@RequestMapping("/get")
public long getServerSysTime(){
	return (new Date()).getTime(); // 返回当前系统时间的毫秒值
}

不知道 axios 是啥的话,就当是 Ajax。这个东西默认是异步请求,说到这里大家可能就会想明白一点,Js代码的逻辑是:通过请求接口修改全局变量,然后将修改后的值放入一个对象中。然而由于方法是异步的,也就是说接口慢的话,当下一行代码提取完 serverTime = ‘空字符串‘ 之后接口才返回结果并赋值给 serverTime 。也就是说因为异步执行的原因导致了接口请求的数据获取不到。然后前端不报错,当执行到 beforeDestory 方法时

那么怎么让方法同步执行呢,就是说我 Ajax 没执行完你们谁也别给我往前走,都阻塞在这儿。

引入 async 和 await 关键字

一定看看上面大佬的博客,详尽的讲解了Vue这俩关键字的用法。
async 修饰的 function 方法 是异步方法。
await 修饰的代码是 阻塞代码,即 await 修饰的代码未执行完会阻塞下一行代码执行。

修改 Js 代码

created: async function() { // Vue 实例创建时执行的 狗子
    // 回调用法,使用回调获取方法的返回值
    await this.getServerTime() // 获取服务器系统时间
    this.timeLog.beginDate = this.serverTime
  },
  methods: {
    // 获取服务器系统时间
    getServerTime: async function () {
      var _this = this
      await this.axios.get('/getServerSysTime')
        .then(res => {
          _this.serverTime = new Date(res.data)
        })
    }
  },
  beforeDestroy: async function () { // Vue Destory方法执行前的 狗子
    // 回调用法,使用回调获取方法的返回值
    var _this = this
    await this.getServerTime() // 获取服务器时间
    this.timeLog.endDate = this.serverTime
    var timeLog= _this.timeLog
    if (_this.timeLog.createDate) {
      _this.axios.post('/保存时间戳的接口', {
        timeLog
      })
    }
  }

这样就解决了明明先请求了接口,还取到空值的情况。

总结

当然还有很多解决方法,比如直接在每处调用 axios,然后在回调方法中执行赋值的操作。

Logo

前往低代码交流专区

更多推荐