JavaScript闭包未捕获var变量 scrollHeight取值始终为0问题
Chrome下滚动深度追踪代码scrollHeight取值为0异常分析
问题对应代码实现
(function() { var debounce = function(func, delay) { var inDebounce; return function() { var context = this; var args = arguments; clearTimeout(inDebounce); inDebounce = setTimeout(function() { func.apply(context, args); }, delay); } } var scrollHeight = document.documentElement.scrollHeight - window.innerHeight; var quarterHeight = scrollHeight / 4; var quarters = 0; var scrollDistance, divisible, percent; document.addEventListener("scroll", debounce(function() { scrollDistance = window.pageYOffset || (document.documentElement || document.body.parentNode || document.body).scrollTop; divisible = Math.trunc(scrollDistance / quarterHeight); if (quarters < divisible) { scrollPercent = divisible * 25; heap.track('Scroll Depth', { percent: scrollPercent }); quarters++; } }, 100)); }());
问题现象
在Chrome浏览器测试上述带防抖的滚动深度追踪代码时,事件监听器回调内依赖的scrollHeight相关计算值始终为0,表现类似闭包未捕获var声明的scrollHeight变量;将scrollHeight的赋值语句移动到闭包内部后,代码功能可正常运行。
异常产生原因
这个问题和闭包捕获逻辑没有关系,核心是代码执行时机错误导致初始值异常,且初始值不会自动更新:
- 这段立即执行函数如果在DOM树构建完成前就运行(比如放在页面
<head>标签内、未等待DOM加载就直接执行),浏览器还没完成页面内容的排版计算,此时读取document.documentElement.scrollHeight得到的结果就是0。 scrollHeight和依赖它计算的quarterHeight都是在立即执行函数的初始化阶段完成赋值的,闭包捕获的是这两个变量的固定初始值,后续哪怕DOM加载完成、页面总高度发生变化,这两个变量也不会自动重新计算,所以滚动触发回调时用到的quarterHeight始终是初始算出来的0,自然会出现计算异常。- 把
scrollHeight的赋值逻辑移到滚动事件的回调内部后,首次触发滚动时DOM必然已经完成渲染,每次执行回调都会实时读取当前的页面总滚动高度,就能拿到正确的计算结果,功能恢复正常。
内容的提问来源于stack exchange,提问作者erotsppa
相关产品推荐
相关产品推荐

