• vue项目created()被调用多次的坑


    一、问题描述

    最近碰到一个奇怪的生产问题:
    正常情况下、前端页面会请求一次后台、然后后台返回信息("处理成功""处理失败")、前端展示;
    后台用aop+redis写了一个防止重复调用的方法,如果5s内同一个用户重复调用同一个接口,就返回"请勿重复调用",前端就会展示这个。

    但是,某几个页面,前端总是会重复调用后端2次,导致用户只能看到"请勿重复调用",无法确认本次操作是成功还是失败,严重影响了用户的正常使用。(虽然是处理成功,但是显示不出来…)

    一开始还怀疑是不是后端的问题,排查了半天,终于锁定了,是前端的问题,vue项目中的created()方法被调用了2次

    继续排查,发现从正常页面跳转到这个问题页面时,确实只跳转了1次,按理说created()方法应该也只触发1次的,但是就是不知道为什么触发了2次。

    二、排查过程

    1.从头开始排查前端项目,vue项目首先会加载main.js,发现这个文件里有:

    import Vcon from './assets/js/vcon'
    
    new Vcon({
      env: ENV
    }, () => {
      new Vue({
        router,
        render: h => h(App)
      }).$mount('#app')
    })
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    发现这个文件里,并不是普通的使用new Vue()创建的页面,而是外面有封装了一个new Vcon()方法,并传了2个参数,其中第一个参数是{ env: ENV },第二个参数是 () => { new Vue({ router, render: h => h(App) }).$mount('#app') }

    2.继续,查看./assets/js/vcon.js文件,发现这个文件里有类似这样的:

    class Vcon {
    
    
    
      constructor (opt, callBack) {
        this.env = opt.env || '' // 记录代码环境
        this.callBack = callBack // 记录回调函数
        // 如果是生产环境
        if (this.env !== 'test') {
          this.prodInit()
          typeof this.callBack === 'function' && this.callBack()
          return
        }
    
        // 如果是测试环境
        if (this.env === 'test') {
          this.testInit()
          return
        }
      }
    
      testInit () {
        import('vconsole').then(({ default: VConsole }) => {
          new VConsole()
          console.log('测试vconsole加载完成')
          typeof this.callBack === 'function' && this.callBack()
        })
      }
      
      prodInit () {
        let _that = this
        window.ISALES.callApp('getUserInfoByNative', {
          callback: function (userInfo) {
            if (userInfo.code === '0') {
              _that.betterStaffNUmber = userInfo.msg.staffNumber
              _that.betterHandler(userInfo)
              return
            }
            alert('获取sdk出错,请稍后再试')
          }
        })
      }
      
      betterHandler (userInfo) {
        if (userInfo.msg.userCode == 'admin') {
          import('vconsole').then(({ default: VConsole }) => {
            new VConsole()
            console.log(`admin的vconsole加载完成`)
            typeof this.callBack === 'function' && this.callBack()
          })
          return
        }else{
          this.callBack()
        }
      }
    
    
    
    }
    
    • 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
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59

    其中,当上一步执行new Vcon()时,实际执行的就是这里的constructor ()方法;
    如果是测试环境,那就执行testInit ()方法,这个还是比较明显的,用来展示vconsole(测试环境一直正常,没有复测出来问题);
    如果是生产环境,那就执行prodInit()方法,然后执行typeof this.callBack === 'function' && this.callBack()方法(这里感觉有些问题,先继续看);

    prodInit()方法里,会执行window.ISALES.callApp方法,这个是个sdk方法(这个前端项目是vue项目,可以打包后把静态页面部署在服务器上;sdk方法是app和ios里的方法,前端只能这样才能调用到、待sdk方法处理完后会触发callback方法);

    sdk方法中,会执行betterHandler()方法,意思是,如果当前app/ios的登录人是admin,那就显示vconsole,否则就不显示。

    3.根据生产created()方法被调用2次、而测试正常的现象,排查到问题方法位置:

        // 如果是生产环境
        if (this.env !== 'test') {
          this.prodInit()
          typeof this.callBack === 'function' && this.callBack()
          return
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    因为prodInit()方法的逻辑中,正常情况下,已经调用过一次typeof this.callBack === 'function' && this.callBack()了,然而执行完prodInit()方法后,又会调用一次typeof this.callBack === 'function' && this.callBack(),所以才导致created()方法被重复调用了2次。

    4.正确代码如下:

        // 如果是生产环境
        if (this.env !== 'test') {
          this.prodInit()
          //这里导致了重复created()
          //typeof this.callBack === 'function' && this.callBack()
          return
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    修改后,发布生产,终于恢复了正常。

    三、备注

    1.vue项目中,有时会自动优化代码格式,导致if后面没有大括号、只有1句,满足条件就执行、不满足就不执行,需要注意。

    2.有时,if没有else,而是if中结尾有个return,此时也类似else,但是容易忽略,需要注意。(这个也是自动优化格式的?还是故意写的难懂了?)

    3.typeof this.callBack === 'function' && this.callBack(),这个的意思是,如果this.callBackfunction类型的,那就会执行后面的this.callBack()方法,然后继续下一步;如果不是function类型的,那就不执行后面的方法,直接继续下一步。(又一个不好理解的高级写法,用if不好吗?)

    4.正常情况下,vue页面的created()方法会在页面初始化的时候执行1次;但是如果代码有问题,就会导致created()方法会在页面初始化的时候执行2次或多次(如本文),这个坑需要注意。

  • 相关阅读:
    面试必备(背)--Redis八股文系列
    汇编语言实验3:DEBUG的使用
    需求管理手册-对需求管理者的要求(10)
    基于JAVA旅游信息网站计算机毕业设计源码+系统+mysql数据库+lw文档+部署
    贪心算法实现规定长度范围的字符串增删改
    设置Json序列化时字段的顺序
    【JavaWeb】一篇承载Ajax、Axios、Json的学习笔记~
    AQS之ReentrantLock源码解析
    今日准备注销CSDN专栏
    【Linux集群教程】13 集群安全防御 - SELinux 功能
  • 原文地址:https://blog.csdn.net/BHSZZY/article/details/128185687