Javascript 同步document.createElement(“脚本”)
是否可以同步调用Javascript 同步document.createElement(“脚本”),javascript,dom,synchronous,Javascript,Dom,Synchronous,是否可以同步调用.js文件,然后立即使用它 <script type="text/javascript"> var head = document.getElementsByTagName('head').item(0); var script = document.createElement('script'); script.setAttribute('type', 'text/javascript'); script.setAttribute('
.js
文件,然后立即使用它
<script type="text/javascript">
var head = document.getElementsByTagName('head').item(0);
var script = document.createElement('script');
script.setAttribute('type', 'text/javascript');
script.setAttribute('src', 'http://mysite/my.js');
head.appendChild(script);
myFunction(); // Fails because it hasn't loaded from my.js yet.
window.onload = function() {
// Works most of the time but not all of the time.
// Especially if my.js injects another script that contains myFunction().
myFunction();
};
</script>
我只是不想太了解内部结构,只想说,“我希望使用这个模块,现在我将使用其中的一些代码。”这看起来像是动态脚本加载的一个不错的概述:
您可以使用“onload”处理程序创建
元素,当浏览器加载并评估脚本时,将调用该处理程序
var script = document.createElement('script');
script.onload = function() {
alert("Script loaded and ready");
};
script.src = "http://whatever.com/the/script.js";
document.getElementsByTagName('head')[0].appendChild(script);
你不能同时做
编辑-有人指出,与表单一样,IE不会在加载/评估的
标记上触发“加载”事件。因此,我认为接下来要做的事情是使用XMLHttpRequest获取脚本,然后自己执行eval()。(或者,我想,将文本填充到您添加的
标记中;eval()
的执行环境受本地范围的影响,因此它不一定会执行您希望它执行的操作。)
编辑-从2013年初开始,我强烈建议寻找一个更强大的脚本加载工具,如。有很多特殊情况需要担心。对于非常简单的情况,现在内置了
异步编程稍微复杂一些,因为
发出请求的方法封装在函数中,而不是遵循请求语句但是用户体验的实时行为可以显著地
更好,因为他们不会看到服务器或网络运行缓慢导致故障
使浏览器看起来好像崩溃了一样同步编程是不礼貌的
和不应在人们使用的应用程序中使用
道格拉斯·克罗克福德
好的,扣上你的座位,因为这将是一次颠簸的旅程。越来越多的人询问如何通过javascript动态加载脚本,这似乎是一个热门话题
它如此流行的主要原因是:
- 客户端模块化
- 更容易的依赖关系管理
- 错误处理
- 性能优势
关于模块化:很明显,管理客户端依赖关系应该在客户端正确处理。如果需要某个对象、模块或库,我们只需请求并动态加载它
错误处理:如果资源失败,我们仍然有机会仅阻止依赖于受影响脚本的部分,或者甚至可以延迟再试一次
性能已经成为网站之间的竞争优势,它现在是搜索排名的一个因素。动态脚本可以模拟异步行为,而不是浏览器处理脚本的默认阻塞方式脚本块其他资源,脚本块进一步解析HTML文档,脚本块UI。现在,通过使用动态脚本标记及其跨浏览器的替代方案,您可以执行真正的异步请求,并仅在相关代码可用时执行它们。您的脚本将与其他资源并行加载,渲染将完美无缺
有些人坚持使用同步脚本的原因是他们已经习惯了。他们认为这是默认的方式,更简单的方式,有些人甚至认为这是唯一的方式
但是,当需要就应用程序的设计做出决定时,我们唯一应该关心的是最终用户体验。在这方面,我们是无法击败的。用户立即得到响应(或说承诺),承诺总比没有好。一块空白的屏幕吓人。开发人员不应该懒得提高感知性能
最后是关于肮脏的一面。要使其跨浏览器工作,您应该做什么:
学会异步思考
将代码组织为模块化
组织代码以很好地处理错误和边缘情况
逐步增强
始终注意适当数量的反馈
这并不漂亮,但很管用:
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
</script>
<script type="text/javascript">
functionFromOther();
</script>
与Pointy一样,也可以创建节点,但仅在FF中。您无法保证脚本在其他浏览器中何时准备就绪
作为一个XML纯粹主义者,我真的很讨厌这一点。但它确实可以预见。您可以轻松地包装那些难看的document.write()
s,这样您就不必查看它们了。您甚至可以进行测试,创建一个节点并附加它,然后返回到document.write()
具有讽刺意味的是,我拥有您想要的东西,但想要更接近您拥有的东西
我以动态和异步方式加载东西,但是使用类似这样的load
回调(使用dojo和XMLHtpRequest)
有关更详细的说明,请参阅
问题是代码在某个地方被赋值,如果您的代码有任何错误,console.error(errorMessage)代码>语句将指示eval()
所在的行,而不是实际错误。这是一个非常大的问题,实际上我正试图转换回
语句(请参阅。这已经太晚了,但对于以后任何想这样做的人,您可以使用以下内容:
function require(file,callback){
var head=document.getElementsByTagName("head")[0];
var script=document.createElement('script');
script.src=file;
script.type='text/javascript';
//real browsers
script.onload=callback;
//Internet explorer
script.onreadystatechange = function() {
if (this.readyState == 'complete') {
callback();
}
}
head.appendChild(script);
}
不久前我写了一篇关于它的短文我习惯于在我的网站上有多个相互依赖的.js文件。为了加载它们并确保以正确的顺序计算依赖关系,我编写了一个函数,加载所有文件,然后在收到所有文件后,eval()
它们。主要缺点是,由于这不会
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
window.onload = function() {
functionFromOther();
};
</script>
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
functionFromOther(); // Error
</script>
dojo.xhrGet({
url: 'getCode.php',
handleAs: "javascript",
content : {
module : 'my.js'
},
load: function() {
myFunc1('blarg');
},
error: function(errorMessage) {
console.error(errorMessage);
}
});
function require(file,callback){
var head=document.getElementsByTagName("head")[0];
var script=document.createElement('script');
script.src=file;
script.type='text/javascript';
//real browsers
script.onload=callback;
//Internet explorer
script.onreadystatechange = function() {
if (this.readyState == 'complete') {
callback();
}
}
head.appendChild(script);
}
function xhrs(reqs) {
var requests = [] , count = [] , callback ;
callback = function (r,c,i) {
return function () {
if ( this.readyState == 4 ) {
if (this.status != 200 ) {
r[i]['resp']="" ;
}
else {
r[i]['resp']= this.responseText ;
}
c[0] = c[0] - 1 ;
if ( c[0] == 0 ) {
for ( var j = 0 ; j < r.length ; j++ ) {
eval(r[j]['resp']) ;
}
}
}
}
} ;
if ( Object.prototype.toString.call( reqs ) === '[object Array]' ) {
requests.length = reqs.length ;
}
else {
requests.length = 1 ;
reqs = [].concat(reqs);
}
count[0] = requests.length ;
for ( var i = 0 ; i < requests.length ; i++ ) {
requests[i] = {} ;
requests[i]['xhr'] = new XMLHttpRequest () ;
requests[i]['xhr'].open('GET', reqs[i]) ;
requests[i]['xhr'].onreadystatechange = callback(requests,count,i) ;
requests[i]['xhr'].send(null);
}
}
xhrs( [
root + '/global.js' ,
window.location.href + 'config.js' ,
root + '/js/lib/details.polyfill.min.js',
root + '/js/scripts/address.js' ,
root + '/js/scripts/tableofcontents.js'
]) ;
//Code User TODO: you must create and set your own 'noEval' variable
require = function require(inFileName)
{
var aRequest
,aScript
,aScriptSource
;
//setup the full relative filename
inFileName =
window.location.protocol + '//'
+ window.location.host + '/'
+ inFileName;
//synchronously get the code
aRequest = new XMLHttpRequest();
aRequest.open('GET', inFileName, false);
aRequest.send();
//set the returned script text while adding special comment to auto include in debugger source listing:
aScriptSource = aRequest.responseText + '\n////# sourceURL=' + inFileName + '\n';
if(noEval)//<== **TODO: Provide + set condition variable yourself!!!!**
{
//create a dom element to hold the code
aScript = document.createElement('script');
aScript.type = 'text/javascript';
//set the script tag text, including the debugger id at the end!!
aScript.text = aScriptSource;
//append the code to the dom
document.getElementsByTagName('body')[0].appendChild(aScript);
}
else
{
eval(aScriptSource);
}
};
var script = document.createElement('script');
script.src = 'http://' + location.hostname + '/module';
script.addEventListener('load', postLoadFunction);
document.head.appendChild(script);
function postLoadFunction() {
// add module dependent code here
}
function include(file){
return new Promise(function(resolve, reject){
var script = document.createElement('script');
script.src = file;
script.type ='text/javascript';
script.defer = true;
document.getElementsByTagName('head').item(0).appendChild(script);
script.onload = function(){
resolve()
}
script.onerror = function(){
reject()
}
})
/*I HAVE MODIFIED THIS TO BE PROMISE-BASED
HOW TO USE THIS FUNCTION
include('js/somefile.js').then(function(){
console.log('loaded');
},function(){
console.log('not loaded');
})
*/
}
// This is a modern JS dependency fetcher - a "webpack" for the browser
const addDependentScripts = async function( scriptsToAdd ) {
// Create an empty script element
const s=document.createElement('script')
// Fetch each script in turn, waiting until the source has arrived
// before continuing to fetch the next.
for ( var i = 0; i < scriptsToAdd.length; i++ ) {
let r = await fetch( scriptsToAdd[i] )
// Here we append the incoming javascript text to our script element.
s.text += await r.text()
}
// Finally, add our new script element to the page. It's
// during this operation that the new bundle of JS code 'goes live'.
document.querySelector('body').appendChild(s)
}
// call our browser "webpack" bundler
addDependentScripts( [
'https://code.jquery.com/jquery-3.5.1.slim.min.js',
'https://stackpath.bootstrapcdn.com/bootstrap/4.5.0/js/bootstrap.min.js'
] )