未捕获的ReferenceError:已定义函数时未定义函数

时间:2019-10-23 11:45:34

标签: javascript html

我有一个已定义但无法在我的DOM中使用的函数。

我正在处理2个文件。可以说 A.js B.js

A.js 中,我有一些类似下面的代码。

(function() {
    var initData = {
        version: "1.0.0",
        host: "xyz.com",
        page_id: "someDynamicID",
    };
    function initVarData(initData) {
        if (!window.ABCD) {
            window.ABCD = initData;
        }
    }
    initVarData(initData);
})();

(function(d, id) {
    function appendToBody(d, el) {
        if (d.head) {
            d.head.appendChild(el);
        } else {
            setTimeout(appendToBody.bind(null, d, el), 500);
        }
    }
    if (d.getElementById(id)) {
        window.ABCD && ABCD.widgets.parse();
        return;
    }

    var js = d.createElement("script");
    js.id = id;
    js.async = true;
    js.src = "https://myserver.com/js/B.js";
    appendToBody(d, js);
})(document, "test");

A.js 中,我定义了一些动态数据(此 A.js 脚本实际上正在加载从后端)。然后 A.js 调用 B.js 加载到DOM中。

B.js 中,我有一些类似下面的代码

(function(window, document) {
  window.bng = function(buttonID) {
    var button = document.getElementById(buttonID);

    if (button) {
      button.addEventListener(
        "click",
        function() {
          alert("This alert is from B.js");
        },
        false
      );
    }
  };
})(window, document);

此功能在控制台中已更新,但在DOM中未更新。

在html中,我调用了 A.js 并使用bng(“ buttonId”)。但出现错误Uncaught ReferenceError:未定义bng。

我已经通过

解决了这个问题
window.addEventListener('load', function() {
  bng("buttonId");
});

但是我想没有onLoad函数。 Facebook正在其SDK中使用此类功能fbq。

1 个答案:

答案 0 :(得分:0)

我认为,如果先加载脚本 B.js (阻止脚本),则问题应得到解决。

注释掉A.js中试图加载B.js的行。

  // var js = d.createElement("script");
  // js.id = id;
  // js.async = true;
  // js.src = "https://myserver.com/js/B.js";
  // appendToBody(d, js); 

并按如下所示编辑HTML。

<head>
    <title>JS Tests</title>
    <script type="text/javascript" src="src/B.js"></script>
    <script type="text/javascript" src="src/A.js"></script>
</head>

您可以尝试下面的代码片段,看看它是否有效。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JS Tests</title>
    <script type="text/javascript" src="https://codepen.io/nithinthampi/pen/abbWzqp.js"></script>
    <script type="text/javascript" src="https://codepen.io/nithinthampi/pen/OJJmPQa.js"></script>
</head>
<body>
    <button id="btn_test">Click Me</button>
    <script>
        window.bng("btn_test");
    </script>
</body>
</html>

如果要采用异步方式(从A.js加载B.js),可以尝试一种可能的方法。

此处脚本 B.js 是异步加载的。

因此,即使在脚本加载和执行之前,您在html中添加的JS代码也会运行并抛出Uncaught ReferenceError: bng is not defined

<body>
    <button id="btn_test">Click Me</button>
    <script>
        // The below code will throw an error as it runs before B.js completes its execution and initializes window.bng()
        window.bng("btn_test");
    </script>
</body>

在这种情况下,我们可以在 A.js 中定义一个函数,例如bng_test(),该函数在应用程序代码执行之前就可以在窗口中使用了。

使 A.js 同步并在其中定义函数bng_test

<head>
    <script src="A.js"></script>
</head>

应用程序代码可以调用在 A.js 中定义的函数window.bng_test,而不是在 B.js

中定义的window.bng

A.js 中的某个地方,定义一个数组(将其称为事件队列)来存储来自应用程序的调用,直到实际功能window.bng准备就绪

如果window.bng_test尚未准备就绪,则新功能window.bng将项目添加到事件队列,否则调用window.bng

const queue = [];
window.bng_test = function(elementId) {
    // Check if the function bng is initialized
    if(window.bng){
      bng(elementId);
    }
    // Add the element to the queue
    else{
      queue.push(elementId);
    }  
};

现在,当执行 B.js 并且window.bng功能可用时,我们可以使用计时器函数清除队列。

  const interval = setInterval(() => {
    if (window.bng) {
      while (queue.length > 0) {
        window.bng(queue.pop());
      }
      clearInterval(interval);
    }
  }, 500);

您可能还需要清除window.beforeunload上的计时器,以避免内存泄漏。

陷阱..

  • 脚本 B.js 速度很慢,用户关闭了窗口/将其导航开了, 电话会丢失。
  • 用户队列中有一些呼叫,已成功执行 B.js ,但 用户关闭的窗口/在计时器清除队列之前先离开。在 在这种情况下,您也可以使用window.beforeunload 清除队列。

尝试下面的代码段。

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>JS Tests</title>
    <script type="text/javascript" src="https://codepen.io/nithinthampi/pen/oNNZybP.js"></script>
</head>
<body>
    <button id="btn_test">Click Me</button>
    <script>
        window.bng_test("btn_test");
    </script>
</body>
</html>