小程序中生命周期钩子函数之外的全局变量要小心使用!!!

之前做的上传水印这块的功能。

有时候由于网络过慢,重复点击的话可能会导致重复打包(生成照片包)。本身做法可以在请求的过程中可以让button禁用,这个就不多讨论。

我当时临时采用的是利用一个变量来控制,请求发出前把变量全局变量isSaving变成true,然后再按钮的点击事件刚进来的时候判读,如果isSaving是true的话那么就return。

saveAndShare(){
    if(isSaving){
      return
    }
    let files = this.data.files;
    let _this = this;
    if(files.length == 0){
      wx.showModal({
        content: '请上传照片!',
        showCancel: false,
        success: function (res) {
          if (res.confirm) {
            _this.chooseImage()
          }
        }
      })
      return
    }
    if(!this.data.title){
      wx.showModal({
        content: '请填写标题',
        showCancel: false,
        success: function (res) {
          _this.setData({
            titleFocus:true
          })
        }
      })
      return
    }
    //验证是不是上传图片后面时才加的水印,这里需要重新拦截处理
    //无需考虑复杂操作,只考虑同款水印,要么都有,要么没有。

    //第一步:验证图片路径有没有水印信息。
    if (!files[0].includes('x-oss-process') && _this.data.encodeWord){
      console.log('执行')
      for(let i = 0;i<files.length;i++){
        files[i] += '?' + _this.data.urlHead + _this.data.encodeWord + _this.data.urlFoot;
      }
    }
    let uid = wx.getStorageSync('id');
    let contentList = [];
    let creator = null;
    for(let i = 0;i < files.length;i++){
      contentList.push({
        sequence:i,
        path: files[i].replace(_this.data.host,'')
      })
    }
    if (app.globalData.userInfo){
      creator = app.globalData.userInfo.nickName;
    }
    isSaving = true
    wx.request({
      url: util.head+'/mp/pr/img/package',
      method: 'POST',
      data: {
        uid,
        watermark: _this.data.word,
        title: _this.data.title,
        notes: _this.data.note,
        creator,
        contentList,
        contentNum: _this.data.files.length
      },
      success: function (res) {
        console.log(res.data)
        if (res.data.status == 'SUCCESS'){
          let id  = res.data.data;
          let creator = app.globalData.userInfo.nickName;
          let face = _this.data.files[0].split('?')[0];
          let title = _this.data.title
          wx.showToast({
            title: '打包成功',
            icon: 'success',
            duration: 1000,
            success: function () {
              setTimeout(function () {
                wx.reLaunch({
                  url: `/pages/msg/msg?id=${id}&creator=${creator}&face=${face}&title=${title}`,
                })
              }, 800)
            }
          })
        }else{
          isSaving = false;
          wx.showToast({
            title: '打包失败',
            icon: 'none',
            duration: 1000
          })
        }
      }
    })
  },
  /**

其实这里我的漏洞是打包成功后应该把变量还原的。但是考虑到成功后会relauch跳转到消息页。

根据官方的路由说明,重启动路由方式执行后,当前的这个上传页面会unload掉。

包括我进入了消息页之后(消息页是非Tab页),然后用switchTab进入了列表页(第二个tab选项),再重新切到第一个tab选项,再点击navigate进入回到上传页面,一系列操作后,

讲道理页面第一步的时候已经卸载掉了,重新进入也是执行onload的,但是为什么isSaving还是true呢?

原因分析:小程序考虑到内存问题的情况下,所以在不同的路由情况会卸载路由前的页面,以缓解内存压力,但是可能这种不是完全的释放内存,Unload卸载的是page对象内的一系列东西,包含data以及钩子函数。

  但是由于isSaving是写在page外面的全局变量,还是存在于微信缓存中的,所以页面卸载后再重新加载,它的值始终是没有重置的。

以下是isSaving的写法:

另外重新试了下,var声明的isSaving 只是相对于组件的全局变量,我在打包成功后的跳转到的消息页page中打印是以下结果:

总结:对于自己的的没有处理好数据导致的小Bug,对小程序的人认识又增进一步真的是喜忧参半。大家对于小程序的page钩子函数,页面unload的理解要多注意,分辨出page之外定义的伪全局变量带来的影响。

追述:小程序page函数,app对象之外的变量类似为顶级变量。需要小程序退出(后台5分钟或者内存超标)才会注销。根据小程序的模块化概念可以单独抽离出js文件,再结合生命周期概念,小程序中定义的页面这一概念来配合对应的onload,onshow,unload等钩子,针对的是page整个对象,所以即使这个a变量和page函数是写在一个wx.j文件里,但我们不能就看成是绑定在一起的整体,事实上页面的卸载是执行的清理掉对应的page对象,而不是释放整个js文件。所以a的值会始终保持一个状态!

ps:以上只是自己的想法和推测,希望路过的大神能多多指正!  

原文地址:https://www.cnblogs.com/hjj2ldq/p/9338404.html