51 document.visibilitychange 的回调在切换 tab 的时候调用了两次

前言

这也是最近机缘巧合之下, 碰到的一个问题

但是 实际上可能在 设计上来说 不算是一个问题, 只是 我们对于 document.addEventListener('visibilitychange', func) 的理解不太够 导致的

主要的问题是 我们增加了一个 'visibilitychange' 的回调, 然后 之后 我们发现 我切换出去, 然后 再切换回来之后, func 调用了两次, 我们期望的 func 应该只是在 切换回来的时候, func 调用一次, 然后 我们就感觉很奇怪

实际的情况是 切换出去的时候 调用了一次 func, 切换回来渲染完成之后 又调用了一次

然后 另外就是 在这种情况下 偶尔会出现 切换过来 请求了 一大片相同的请求的情况

 

 

测试用例

测试用例如下, 在 Vue 组件初始化的时候 向 document 注册了一个 visibilitychange 的回调

<template>
  <div class="testParent">
    x + y = {{z}}
  </div>
</template>

<script>

  export default {
    name: "HelloVisibilityChange",
    components: {
    },
    props: {

    },
    data() {
      return {
        z: 5,
      }
    },
    created() {

    },
    mounted() {
      document.addEventListener('visibilitychange', () => {
        let x = 2, y = 3
        this.z = x + y
        console.log("x + y = " + this.z)
      })
    },
    methods: {

    },
  }
</script>

<style>

</style>

 

我把这个页面切换出去, 然后 切换回来之后, func 中的回调执行了两次

这个 最开始 也很懵

cbfcdae4e93149d2bc50f5247f2d4094.png

 

 

visiblechange 的调用时机

切换出去的时候 调用了一次 func, 切换回来渲染完成之后 又调用了一次

调整一下 visibilitychange 的回调, 增加一行如下 日志

然后 操作如下, 刷新当前页面, 点击其他 tab 页面, 等待十秒, 切换回目标 tab 页面, 查看情况

06b1847d0a1744d399a489f45d654fa6.png

 

这里的日志输出, 可以证实上面的结论

也可以查看 document.visibilitychange 事件处理的官方文档, 也可以看到 如上的信息

f04f290b9bae43b290866c612ec4e544.png

 

 

为什么出现了偶尔切换回来十几个事件处理的情况?

这个是 热部署相关机制导致的问题

比如 初始化的时候进入 mounted 在 document 上面增加了一个 visibilitychange 的回调处理

然后 调整了代码之后, 热部署相关处理 重新更新页面, 然后 会重新执行 moutned 中的相关处理 又在 document 上面增加了一个 visibilitychange 的回调处理

 

我们这里 做一个如下的测试

1.初始化刷新页面 
2.在 visibilitychange 的回调上面增加一行无用的代码 let a = “dummy”
3.等待页面热部署完成
4.在 visibilitychange 的回调上面增加一行无用的代码 let b = “dummy”
5.等待页面热部署完成
6.切换出去, 再切换回来
7.观察现象

 

第一个框是 上面的 2, 3 完成之后的日志, 首先就是初始化的 func1 在 hidden 的时候调用了一次, 然后是 初始化的func1 + 热部署新增的func2 在 visible 的时候调用而一次

第二个框是 上面 4, 5 完成之后的日志, 首先是 初始化的func1, 热部署新增的 func2 在 hidden 的时候调用了一次, 然后是 初始化的func1 + 热部署新增的func2 在 visible 的时候调用而一次, 没有本次热部署增加的 func3 是这个有一定的不确定性, 可能 visible 的时候 事件 func3 还未绑定好

第三个框是 6, 7 完成之后的日志, 首先是 初始化的func1, 热部署新增的 func2, func3 在 hidden 的时候调用了一次, 然后是 初始化的func1, 热部署新增的 func2, func3 在 visible 的时候调用了一次

可以根据代码的行号来区分 初始化的func1 和 热部署增加的func2, func3

05f30a90816c4ad692fd555453df1de7.png

 

更新完成之后, 代码上下文如下

初始化的 func1 的两行日志输出分别是, 第28, 29 行

热部署新增的 func2 的两行日志输出分别是, 第29, 30 行

热部署新增的 func3 的两行日志输出分别是, 第30, 31 行

a9140b32cc684579a4372b9beb8da63a.png

 

 

 

 

 

  • 16
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值