前言
这也是最近机缘巧合之下, 碰到的一个问题
但是 实际上可能在 设计上来说 不算是一个问题, 只是 我们对于 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 中的回调执行了两次
这个 最开始 也很懵
visiblechange 的调用时机
切换出去的时候 调用了一次 func, 切换回来渲染完成之后 又调用了一次
调整一下 visibilitychange 的回调, 增加一行如下 日志
然后 操作如下, 刷新当前页面, 点击其他 tab 页面, 等待十秒, 切换回目标 tab 页面, 查看情况
这里的日志输出, 可以证实上面的结论
也可以查看 document.visibilitychange 事件处理的官方文档, 也可以看到 如上的信息
为什么出现了偶尔切换回来十几个事件处理的情况?
这个是 热部署相关机制导致的问题
比如 初始化的时候进入 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
更新完成之后, 代码上下文如下
初始化的 func1 的两行日志输出分别是, 第28, 29 行
热部署新增的 func2 的两行日志输出分别是, 第29, 30 行
热部署新增的 func3 的两行日志输出分别是, 第30, 31 行
完