wx.previewImage坑之setInterval倒计时效果被其中断问题

本文探讨了在小程序开发过程中遇到的一个问题:在进行倒计时的同时触发图片预览导致倒计时被中断的现象。分析了问题的原因,并提出了解决方案。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这个问题,挺新颖的。是在一次开发小程序中遇到的,就是在倒计时的时候会在倒计时在某个时间时给用户展示一个图片,用户可点击这个图片放大查看,然后就在点击查看图片(要经过网络请求获得)的时候,setInterval设置的倒计时被中断,即被清掉了。这显然不是我要得效果,我要得效果是即使用户点击图片放大查看也不影响倒计时的运行。

WXML部分:

<view class='countDown'>倒计时:<text class='countDownNum'>{{countDownNum}}</text>s</view>
<view class='relativeImageView'><image class='relativeImage' src='{{imageUrl}}' bindtap='showBigImage'></image></view>

原JS部分:

data: {
    timer: ''
},
countDown: function (){
    let that = this;
    let showTipTime = 30;
    let countDownNum = 60;
    that.setData({
      timer: setInterval(function () {
        countDownNum--;
        that.setData({
          countDownNum: countDownNum
        })
        if (countDownNum == showTipTime) {
          that.setData({
            imageInfoHidden: false
          })
        } else if (countDownNum == 0) {
          clearInterval(that.data.timer);
        }
      }, 1000)
    })  
  },

//图片点击,预览大图效果
  showBigImage:function(){
    let that = this;
    let imageUrl = wx.getStorageSync("imageUrl");//这个imageUrl是之前发送请求保存下来的图片路径
    wx.previewImage({
      current: imageUrl,
      urls: [imageUrl],
      complete: function(){
      },
    })
  },

大家可以将代码复制,然后去查看效果,发现点击查看图片后,然后点击图片,图片会消失,但是倒计时也停止,即被清掉了。

那么怎么分析这个问题并解决呢?

我给出的分析是这样的(是我自己分析的,肯定会有不足之处,希望大神看了勿喷,还请指正,感激不尽):

因为setInterval和setTimeout均属异步线程(严格上应该要被称为伪异步编程,毕竟还是那句老话,js是单线程的),HTTPS请求默认也是异步执行的,然而js执行代码时,是单线程的,在整个页面渲染完成之后,js需要执行的基本上都是用户的操作,即与用户的交互,其中包括资源请求等。

由于setInterval产生的倒计时效果属于异步线程,按道理来说,只要界面内有用户的操作,那么便优先执行用户的操作,然后再执行异步线程里的内容。这里我这么解释吧,js执行代码是单线程的,异步线程里的任务是在同步线程执行完之后再执行的,也就是说,执行的顺序是同步>异步,js执行代码相当于把异步任务放在了同步任务的最后面,异步线程里的任务跟同步线程里的代码一样,是要按照从上至下,从左至右的顺序执行。

好,那么当用户点击预览图片这个事件(同步),那么先执行这个事件内的具体任务,我们发现showBigImage函数里有一个请求图片的异步操作,这个时候,由于先进入到了showBigImage事件,随后要异步请求图片,js又是单线程的,所以它只好先把setInterval关掉,停止对它的操作,优先去执行获取图片的异步操作,然而获取图片之后,本应该要返回再执行setInterval的,但由于js将先清掉了(相当于clearInterval),所以倒计时会停止。

解决:

很明显,我们要在请求imageUrl之后再次启动定时器,但是这样话有延迟,意思是请求到imageUrl需要点时间(虽然这个时间在网络环境很好时很短),倒计时会不真实,所以倒计时函数暂时不能写进complete回调里,那么到底怎么解决呢?

将倒计时函数写在请求imageUrl之前?博主我试过,当时是可以的,为何这样说?是因为当时测试的时候只测试了两遍,两遍都成功了,便以为可以,但是后台我又测试了几遍,尤其是点击预览图片的时候,这个时候,定时器都不会被关闭。从而出现负数的情况,很是尴尬啊。

所以在每次点击图片预览大图时,如果将倒计时写在请求之前,都会重新启动异步线程setInterval,由于要隔1s才会进入到倒计时函数countDown,那么在这1s内,js会去执行请求imageUrl,即在请求imageUrl之后,setInterval(也就是倒计时效果会被停止)会被中断。所以为了防止这种情况,理应该要把setInterval异步线程的执行提到获取imageUrl的前面(这里也体现到了js是单线程解析代码的)。

但是不行,哎,我个人觉得是wx.previewImage接口的坑,而且很奇葩的是,我设计的倒计时到指定时间后会跳转到另外一个页面,但是如果一直将界面停留在预览图片界面(如上图左边),即使页面跳转了,这个窗口依旧不会消失!!!博主现在暂时想不出有什么方法可以解决,希望有高手指点...

最后为了妥协这个坑(我实在是跳不出来啊......),下面是升级后的代码:

data: {
    timer: ''
},
countDown: function (){
    let that = this;
    let showTipTime = 30;
    let countDownNum = 60;
    that.setData({
      timer: setInterval(function () {
        countDownNum--;
        that.setData({
          countDownNum: countDownNum
        })
        if (countDownNum == showTipTime) {
          that.setData({
            imageInfoHidden: false
          })
        } else if (countDownNum == 0) {
          clearInterval(that.data.timer);
        }
      }, 1000)
    })  
  },

//图片点击,预览大图效果
  showBigImage:function(){
    let that = this;
    let imageUrl = wx.getStorageSync("imageUrl");//这个imageUrl是之前发送请求保存下来的图片路径
    wx.previewImage({
      current: imageUrl,
      urls: [imageUrl],
      complete: function(){
        that.countDown();//其实就在这里增加了一个调用倒计时的函数
      },
    })
  },

 

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值