[英]How to know that dynamically created script tag was executed?
我正在动态创建一个脚本标签:
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.defer = true;
script.async = true;
script.text = 'some my javascript content here';
head.appendChild(script);
script.onload = function () {
// this never get fired..
debugger;
}
当脚本在其他代码块中执行时如何得到通知? 也许一些事件?
我能够通过向脚本添加 ID,然后在 JS 中手动触发该 DOM 元素上的加载事件来实现此目的。 仅在 Chrome 中测试,根据MDN在旧版 IE 中会出现问题)。
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.id = 'testing';
script.defer = true;
script.async = true;
script.onload = function () {
console.log('The script is loaded');
}
script.text = ["console.log('This is from the script');",
"var script = document.getElementById('testing');",
"var event = new UIEvent('load');",
"script.dispatchEvent(event);"].join('');
head.appendChild(script);
在现代浏览器中,你可以使用Mutation Observer来检测元素的变化——在这种情况下是head
。 像这样的东西:
observer = new MutationObserver(function (m) {
// This will be fired
});
observer.observe(document.head, {childList: true});
不幸的是,这在 IE < 11 中不起作用,但似乎onload
在 IE 中被触发,因此您可以将它用于 IE。
代码每 100 毫秒检查一次脚本是否附加到 DOM。 您可以在整个应用程序中的任何地方使用它,而无需事件侦听器和调度事件。 同样,如果脚本没有附加到您设置的时间间隔内,您可以看到代码将抛出错误的时间间隔。
const waitForScriptToLoad = (scriptName, checkTimeMs, timeOutMs) => {
let elapsedTime = 0;
return new Promise((resolve, reject) => {
setTimeout(x => reject('script: ' + scriptName + ' Timed out!')
, timeOutMs)
const time = setInterval(() => {
elapsedTime += checkTimeMs;
if (document.body.innerHTML.indexOf(scriptName) > -1) {
resolve(
{
response: 'script: ' + scriptName + ' found!',
time: (elapsedTime / 1000).toFixed(2) + 's'
});
clearInterval(time);
}
}, checkTimeMs)
})
}
waitForScriptToLoad('script_name.js', 100, 20000)
.then(res => console.log(res))
.catch(err => console.log(err))
根据我的发现,您可以简单地执行以下操作:
var script = document.createElement("script");
script.innerHTML = "console.log('(1) hello from inline script');"
document.head.appendChild(script);
setTimeout(
function() {
console.log("(2) we're done!");
},
0 // 👈 zero timeout
);
为什么会这样:零超时基本上意味着“下一个事件周期” - 因为它是一个内联<script>
节点,所以当你 append 它到<head>
时,任何网络活动都没有延迟,这意味着浏览器将执行在下一个事件周期之后立即内联脚本。
只是不要使用load
事件,你对 go 很好。
在 IE 10 + 11 和当前版本的 Chrome、Firefox、Edge、Opera 和 Safari 中测试并工作。
如果您的脚本需要同时支持内联脚本和外部脚本,只需使用if (script.src)
之类的条件来测试脚本是否为外部脚本 - 然后有条件地使用load
事件侦听器或零超时。
在设置脚本源之前,您需要定义onload
函数。 但是,正如 Teemu 告诉我的那样,由于您是通过text
属性编写 javascript,因此onload
事件永远不会触发。 您最好的选择是拥有一个外部 js 文件并通过src
属性加载它。
顺序应该是:
- 将脚本元素附加到 DOM
- 定义加载函数
- 定义
src
var head = document.getElementsByTagName('head')[0];
var script = document.createElement('script');
script.type = 'text/javascript';
script.charset = 'utf-8';
script.defer = true;
script.async = true;
head.appendChild(script);
script.onload = function () {
// this never get fired..
debugger;
}
script.src = 'scriptName.js';
然后你的 onload 事件应该被触发,你可以插入一个console.log("script has loaded!");
函数中的语句。
将代码提取到 .js 文件中。
添加script.src = 'yourjs.js';
到脚本。
当脚本被添加到 DOM 时,.js 文件会被沉浸式执行。
在yourjs.js
添加一个if(console){console.debug('helloworld.');}
,您将看到该消息。
另一种解决方案(不使用onload
或src
)
window.onload = function(){
var script = document.createElement('SCRIPT'),
content = 'console.debug("Hello Kitty");'; // or console.log
script.type = 'text/javascript';
try {
script.appendChild(document.createTextNode(content));
} catch (e) {
script.text = content;
} finally {
document.getElementsByTagName("HEAD")[0].appendChild(script);
}
};
工作演示(在 IE、FF、Chrome 和 Opera 上测试)
出于测试目的,您始终可以添加对 alert() 函数的调用。 但是,在查看您的代码后,我不确定我在其中看到了任何实际执行函数调用的内容。 在执行 appendChild() 之前,可能应该将“onload”事件处理程序添加到动态创建部分。
不久前我写了一些代码来做一些动态脚本创建,它工作正常。 我的代码有两个主要功能,一个创建脚本(一堆),从“.js”文件加载数据,另一个调用这些脚本中的函数,按名称确定的顺序(使用“eval ()“ 功能)。 你的函数没有任何我能看到的名字......我知道很多人不喜欢使用 eval() 函数,但只要它唯一调用的东西是你完整写的东西,应该没问题。
这段代码让浏览器,而不是 Web 服务器,动态创建一个可点击链接项目的菜单(每个可点击链接看起来像一个普通的超链接,但实际上是一个 JavaScript 结构,浏览器必须启用 JavaScript 才能使链接工作--但是它必须启用 JavaScript 才能创建菜单,所以没问题!):
var F00, F01, F02, F03, F04, F05, F06, F07, F08, F09,
F10, F11, F12, F13, F14, F15, F16, F17, F18, F19;
var dat = new Array();
var form, script, str, st2, tmp, tmp2, dtno, indx, unde;
function initialize()
{ window.name="MyMenu";
form = document.getElementById('MENU');
for(indx=0; indx<20; indx++)
{ str = "0" + indx;
tmp = str.length - 2;
str = str.substr(tmp);
script = document.createElement('script');
script.type = 'text/javascript';
script.src = str + ".js";
form.appendChild(script);
}
window.setTimeout("BuildMenu();", 1000); //delay is necessary;
// scripts are actually only loaded after the function ends,
// and you need to allow time for it to finish
// before calling the functions in those scripts.
return;
}
请注意,此代码已准备好处理 20 个菜单项,即使您当前只有 5 个菜单项准备就绪。 如果 20 个最大的“.js”文件中的某些文件不存在,则上述函数不会崩溃。
function BuildMenu()
{ dtno = 0;
for(indx=0; indx<20; indx++)
{ str = "0" + indx;
tmp = str.length - 2;
str = "F" + str.substr(tmp);
tmp = eval(str);
if(tmp != unde) //no value is assigned to 'unde'; it is undefined;
//this is a valid way to find out
//whether or not a ".js" script existed/was-loaded.
dat[dtno++] = eval(str + "()");
}
dat.sort();
for(indx=0; indx<dtno; indx++)
{ str = "0" + indx;
tmp = str.length - 2;
str = "W" + str.substr(tmp);
tmp = document.getElementById(str);
tmp.innerHTML = "<a onclick=\"window.open('" + dat[indx][1] + "', 'MyMenu');\" style=\"color:#0000ff;text-decoration:underline;cursor:pointer;\">" + dat[indx][0] + "</a> " + dat[indx][2] + "<br />";
}
return;
}
在网页的 HTML 代码中,有这样的:
<body onload="initialize();>
<br />
<form id="MENU" action="" onsubmit="return false;">
<span id="W00"> </span>
<span id="W01"> </span>
<span id="W02"> </span>
<span id="W03"> </span>
<span id="W04"> </span>
<span id="W05"> </span>
<span id="W06"> </span>
<span id="W07"> </span>
<span id="W08"> </span>
<span id="W09"> </span>
<span id="W10"> </span>
<span id="W11"> </span>
<span id="W12"> </span>
<span id="W13"> </span>
<span id="W14"> </span>
<span id="W15"> </span>
<span id="W16"> </span>
<span id="W17"> </span>
<span id="W18"> </span>
<span id="W19"> </span>
</form>
以下是“00.js”文件的一些示例代码:
<!--
function F00()
{ return ["Menu Item Alpha", "./Alpha.htm", "Select Web Page Alpha"];
}
-->
请注意,该函数仅返回 3 个数组元素(字符串)。 BuildMenu() 函数使用这些字符串构建网页上的菜单,部分是通过修改 span 元素的 innerHTML。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.