Jos*_*son 73 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('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>
Run Code Online (Sandbox Code Playgroud)
这是简化的.在我的实现中,createElement的东西在一个函数中.我想在函数中添加一些东西,可以在返回控件之前检查某个变量是否被实例化.但是,当我从另一个我无法控制的网站中包含js时,仍然存在一个问题.
思考?
编辑:
我现在已经接受了最好的答案,因为它为正在发生的事情提供了一个很好的解释.但如果有人对如何改进这一点有任何建议我会向他们开放.这是我想做的一个例子.
// Include() is a custom function to import js.
Include('my1.js');
Include('my2.js');
myFunc1('blarg');
myFunc2('bleet');
Run Code Online (Sandbox Code Playgroud)
我只是想从不必知道的内部太多,只能够说,保持"我希望用这个模块,现在我会使用一些代码吧."
Poi*_*nty 120
您可以<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);
Run Code Online (Sandbox Code Playgroud)
你不能同步做到这一点.
编辑 - 有人指出,对于形式而言,IE不会在<script>正在加载/评估的标签上触发"加载"事件.因此,我认为接下来要做的就是使用XMLHttpRequest获取脚本然后eval()自己获取.(或者,我想,将文本填充到<script>您添加的标记中;执行环境eval()受本地范围的影响,因此它不一定会按照您希望的方式执行.)
编辑 - 截至2013年初,我强烈建议您研究一个更强大的脚本加载工具,如Requirejs.有很多特殊情况需要担心.对于非常简单的情况,有yepnope,现在已经内置到Modernizr中.
Jos*_*son 23
这不是很好,但它有效:
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
</script>
<script type="text/javascript">
functionFromOther();
</script>
Run Code Online (Sandbox Code Playgroud)
要么
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
window.onload = function() {
functionFromOther();
};
</script>
Run Code Online (Sandbox Code Playgroud)
该脚本必须包含在单独的<script>标记中或之前window.onload().
这不起作用:
<script type="text/javascript">
document.write('<script type="text/javascript" src="other.js"></script>');
functionFromOther(); // Error
</script>
Run Code Online (Sandbox Code Playgroud)
创建节点也是如此,就像Pointy那样,但仅限于FF.您无法保证脚本何时可以在其他浏览器中使用.
作为XML纯粹主义者,我真的很讨厌这个.但它确实可行.你可以轻松地包裹那些丑陋的document.write()s,这样你就不必看它们了.您甚至可以进行测试并创建一个节点并附加它然后重新开始document.write().
zco*_*rts 16
这是迟到的,但为了将来参考任何想要这样做的人,您可以使用以下内容:
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);
}
Run Code Online (Sandbox Code Playgroud)
异步编程稍微复杂一些,因为发出请求的结果封装在函数中而不是跟在请求语句之后.但是用户体验的实时行为可以明显更好,因为他们不会看到缓慢的服务器或缓慢的网络导致浏览器表现得好像已经崩溃.同步编程是不尊重的 ,不应该在人们使用的应用程序中使用.
Douglas Crockford (YUI博客)
好吧,扣你的座位,因为这将是一个坎坷的旅程.越来越多的人质疑通过javascript动态加载脚本,这似乎是一个热门话题.
这成为如此受欢迎的主要原因是:
关于模块化:很明显,应该在客户端处理管理客户端依赖关系.如果需要某个对象,模块或库,我们只需要它并动态加载它.
错误处理:如果资源失败,我们仍然有机会仅阻止依赖于受影响脚本的部分,或者甚至可能再次尝试延迟.
性能已成为网站之间的竞争优势,它现在是搜索排名因素.动态脚本可以做的是模仿异步行为,而不是浏览器处理脚本的默认阻塞方式.脚本阻止其他资源,脚本阻止进一步解析HTML文档,脚本阻止 UI.现在使用动态脚本标记及其跨浏览器替代方案,您可以执行真正的异步请求,并仅在相关代码可用时执行它们.即使使用其他资源,您的脚本也会并行加载,渲染将完美无瑕.
有些人坚持使用同步脚本的原因是因为他们习惯了它.他们认为这是默认方式,这是更简单的方式,有些人甚至认为这是唯一的方法.
但是,当需要决定应用程序的设计时,我们唯一应该关心的是最终用户体验.而在这个领域异步不能打败.用户得到即时回应(或说承诺),承诺永远比没有好.一个空白的屏幕吓到了人们.开发人员不应该懒惰以提高感知性能.
最后一些关于脏的方面的话.你应该怎么做才能让它跨浏览器工作:
小智 7
上面的答案为我指明了正确的方向。这是我工作的通用版本:
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
}
Run Code Online (Sandbox Code Playgroud)
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');
})
*/
}
Run Code Online (Sandbox Code Playgroud)