javascript 如何知道动态创建的脚本标签被执行了?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/25688786/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to know that dynamically created script tag was executed?
提问by Kosmetika
I'm creating a script tag dynamically:
我正在动态创建脚本标签:
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;
}
How to get notified when script was executed inside other code block? Maybe some event?
如何在其他代码块中执行脚本时得到通知?也许是什么活动?
采纳答案by pherris
I was able to get this to work by adding an ID to the script, then in the JS, manually firing the load event on that DOM element. Tested only in Chrome, will have issues in older IE according to MDN).
我能够通过在脚本中添加一个 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);
回答by Teemu
In modern browsers you could use Mutation Observerto detect changes in an element – head
in this case. Something like this:
在现代浏览器中,您可以使用Mutation Observer来检测元素的变化——head
在这种情况下。像这样的东西:
observer = new MutationObserver(function (m) {
// This will be fired
});
observer.observe(document.head, {childList: true});
Unfortenately this doesn't work in IE < 11, but it seems that onload
is fired in IE, so you can use it for IEs.
不幸的是,这在 IE < 11 中不起作用,但似乎onload
在 IE中被触发,因此您可以将它用于 IE。
回答by Eugen Sunic
The code checks every 100ms if the script got appended to the DOM. You can use it anywhere across your app without the need of event listeners and dispatch events. Likewise, you can see a time interval for which the code will throw an error if the script doesn't append in the time interval that you've set.
代码每 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))
回答by hex494D49
Another solution (without using onload
or src
)
另一种解决方案(不使用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);
}
};
Working demo(Tested on IE, FF, Chrome and Opera)
工作演示(在 IE、FF、Chrome 和 Opera 上测试)
回答by Sterling Archer
You need to define the onload
function before you set the script source. However, as Teemu has told me, since you are writing the javascript via the text
property, the onload
event never fires. Your best option would be to have an external js file and load it via the src
attribute.
您需要onload
在设置脚本源之前定义函数。但是,正如 Teemu 告诉我的那样,由于您是通过text
属性编写 javascript ,因此该onload
事件永远不会触发。您最好的选择是拥有一个外部 js 文件并通过src
属性加载它。
The order should be:
顺序应该是:
- Append script element to DOM
- Define onload function
- define
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';
Then your onload event should fire, and you can insert a console.log("script has loaded!");
statement into the function.
然后你的 onload 事件应该被触发,你可以console.log("script has loaded!");
在函数中插入一条语句。
回答by Grim
Extract the code to a .js-file.
将代码提取到 .js 文件中。
Add script.src = 'yourjs.js';
to the Script.
添加script.src = 'yourjs.js';
到脚本。
The .js-file is immerdently executed when the script is added to the DOM.
当脚本被添加到 DOM 时,.js 文件会被沉浸式执行。
Add a if(console){console.debug('helloworld.');}
ontop of the yourjs.js
and you will see the message.
添加if(console){console.debug('helloworld.');}
的ontop的yourjs.js
,你会看到该消息。
回答by vernonner3voltazim
For testing purposes you can always add a call to the alert() function. However, after looking at your code I'm not sure I see anything in it to actually do the calling of the function. That "onload" event handler probably should be added to the dynamic creation section, before you do the appendChild().
出于测试目的,您始终可以添加对 alert() 函数的调用。但是,在查看您的代码后,我不确定我在其中看到了任何实际执行函数调用的内容。在执行 appendChild() 之前,可能应该将“onload”事件处理程序添加到动态创建部分。
I wrote some code a while back to do some dynamic script creation, and it works fine. My code has two main functions, one that creates the scripts (a bunch of them), loading data from ".js" files, and another that calls the functions in those scripts, in a sequence determined by their names (using the "eval()" function). Your function doesn't have any name that I can see... I know that a lot of folks frown on using the eval() function, but so long as the only thing being called by it is something YOU wrote in its entirety, it should be fine.
不久前我写了一些代码来创建一些动态脚本,它运行良好。我的代码有两个主要功能,一个创建脚本(一堆),从“.js”文件加载数据,另一个调用这些脚本中的函数,按名称确定的顺序(使用“eval ()“ 功能)。你的函数没有任何我能看到的名字......我知道很多人不喜欢使用 eval() 函数,但只要它唯一调用的是你完整编写的东西,应该没问题。
This code lets the BROWSER, not the Web Server, create a menu of clickable-link items dynamically (each clickable link looks like an ordinary hyperlink, but is actually a JavaScript construct, and the browser has to have JavaScript enabled for the link to work --but then it had to have JavaScript enabled to create the menu, so no problem!):
这段代码让浏览器,而不是 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;
}
Note this code is PREPARED to handle 20 menu items, even if you only have 5 items currently ready to be on the menu. The above function doesn't crash if some of the 20 maximum ".js" files don't exist.
请注意,此代码已准备好处理 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;
}
In the HTML code for the web page, there is this:
在网页的 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>
Here is some sample code for the "00.js" file:
以下是“00.js”文件的一些示例代码:
<!--
function F00()
{ return ["Menu Item Alpha", "./Alpha.htm", "Select Web Page Alpha"];
}
-->
Note the function simply returns 3 array-elements (strings). The BuildMenu() function uses those strings in constructing the menu on the web page, partly by modifying the innerHTML of the span elements.
请注意,该函数仅返回 3 个数组元素(字符串)。BuildMenu() 函数使用这些字符串构建网页上的菜单,部分是通过修改 span 元素的innerHTML。