解决此“ReferenceError:函数未定义”的最佳方法?

问题描述

我有一个包含多个组件的 AEM 页面,这些组件有一个 .js 文件,其中包含一个包含所有客户端逻辑的函数。然后我们在组件的 HTML 中调用函数

<script>
    window.bootstrap_component(function() {
        init_component_name();
    });
</script>

如前所述,init_component_name 是一个包含我们需要的所有逻辑的函数名称

function init_component_name() {
    //DO STUFF
}

包装器 bootstrap_component 函数在我们所有页面的共享 head.html 中定义为:

<script>
    window.bootstrap_component = function (handler) {
        if (typeof handler === 'function') {
            if (document.readyState === "complete" || document.readyState === "loaded" || document.readyState === "interactive") {
                handler();
            } else {
                document.addEventListener("DOMContentLoaded",function() {
                    handler();
                });
            }
        }
    }
</script>

这工作正常,我们没有任何实际问题,但我们最近开始使用 Bugsnag 进行错误监控和报告,我们收到几乎每个组件的报告,在页面上说 ReferenceError 所以/和/所以 init_component_name() 不是定义。

我认为发生这种情况的原因是因为 init_component_name() 函数没有在 script 标签中声明,并且因为这个 function(init_component_name) 已经附加到它正在执行的窗口对象上,你看不到任何控制台错误

如果我是对的,会修改这些脚本标签来像这样工作吗?

<script>
    window.bootstrap_component(function() {
        window.init_component_name();
    })
</script>

我的一个同事想为 init_component_name 函数添加一个像 1ms 这样的超时时间,但它让我感到不适。有没有更明智的做法?

解决方法

如果我是对的,会修改这些脚本标签来像这样工作吗?

window.bootstrap_component(function() {
    window.init_component_name();
})

是的,但是您会遇到将多个数据写入全局命名空间 window 的问题,这并不理想。如果另一个第三方脚本决定覆盖它怎么办?

理想情况下,您应该有一个命名空间并将所有内容都放在那里,并且只将该命名空间写入 window

window.something = {};
something.bootstrap_component = { //...

something.init_component_name = () => {
    //DO STUFF
}

或者更好的是,使用 modules(尽管这需要一些简单的代码重构)。

不要做超时黑客。真的,真的太可怕了;如果脚本由于某种原因加载时间超过一秒怎么办?您还强迫您的 UI 等待一秒钟,这通常是不必要的。这种 hack 往往体现在没有正确考虑时间顺序和范围的地方。