我有一个已定义但无法在我的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。
答案 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
上的计时器,以避免内存泄漏。
陷阱..
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>