Lazy loading JavaScript and Inline JavaScript
我注意到在我的站点(用于工作)的 中,有很多 和 标签。还有更多只为特定页面加载的javascript/css文件(我们正在使用codeigner,文件路径被传递到头视图)。
我正在考虑使用条件/异步加载程序(例如yepnope.js、head.js等),但我注意到这样做有一个小问题。
在我们的视图中,有内联的javascript,有些使用$(function(){}) ,有些使用$(document).ready(function(){}) ,有些使用jquery的代码不在ready 块中。
如果不编辑每个视图文件将其代码包装在函数中,并且在加载JS文件时调用它,是否有一种方法可以延迟内联代码,直到异步加载javascript?
不,但是你可以通过使用window.$ = waitUntilCodeLoaded 使你的工作更容易。这样,您只更改了一半的内联代码。事实上,内联代码是不好的,使它都是外部的
@雷诺斯:我在考虑把所有代码移到他们自己的文件中,但是我们有很多视图,这需要一段时间。我希望有一个快速,老土的解决办法,我可以做。
Raynos是对的
我知道我应该将所有脚本移动到它们自己的文件中,但是是否有一个快速、黑客的解决方案,我可以使用它让内联javascript在我想要的时候运行?
还有兴趣:hacks.mozilla.org/2017/09/…
实际上,您可以使用Lazyload内联JavaScript:1-将内联脚本中的类型参数更改为:text/delayscript
从
1 2 3
<! – Inline Script –>
< script type= "text/javascript" language= "javaScript" >
/* Code */
到
1 2 3
<! – Inline Script –>
< script type= "text/delayscript" >
/* Code */
给脚本标记一个自定义的mime类型text/delayscript会强制浏览器忽略其内容(请注意,完全忽略它将默认为text/javascript)。
2-延迟加载所有内联脚本一旦heads.js(或您可能使用的其他框架)确认它懒惰地加载了所有外部js,您就可以获取所有自定义脚本标记的内容并将它们插入页面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
head.ready ( function ( ) {
var
_head = document.getElementsByTagName ( "head" ) [ 0 ] ,
_script = document.createElement ( 'script' ) ,
_scripts = document.getElementsByTagName ( "script" ) ,
_txt = "text/delayscript" ,
_contents = [ ]
;
for ( var i= 0 , l= _scripts.length ; i< l; i++ ) {
var _type = _scripts[ i] .getAttribute ( "type" ) ;
if ( _type && _type.toLowerCase ( ) == _txt)
_contents.push ( _scripts[ i] .innerHTML )
}
_script.type = 'text/javascript' ;
_script.innerHTML = _contents.join ( "" ) ;
_head.appendChild ( _script) ;
} ) ;
为了更加优雅,您实际上可以将内联脚本保持在DOM树的原始层次结构中,而不是像我上面建议的那样,将标记的内联脚本标记替换为具有mime-type-text/javascript的新标记,从而将它们的所有内容都插入到一个脚本中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
head.ready ( function ( ) {
var
_scripts = document.getElementsByTagName ( "script" ) ,
_doc = document,
_txt = "text/delayscript"
;
for ( var i= 0 , l= _scripts.length ; i< l; i++ ) {
var _type = _scripts[ i] .getAttribute ( "type" ) ;
if ( _type && _type.toLowerCase ( ) == _txt)
_scripts[ i] .parentNode .replaceChild ( ( function ( sB) {
var _s = _doc.createElement ( 'script' ) ;
_s.type = 'text/javascript' ;
_s.innerHTML = sB.innerHTML ;
return _s;
} ) ( _scripts[ i] ) , _scripts[ i] ) ;
}
} ) ;
嘿,真聪明。因此,告诉浏览器忽略脚本标记,然后在加载外部脚本时将它们重新加载到页面中。我喜欢它。
只要没有document.write在内联脚本中,这就可以工作。因此,除了我上面提到的方法外,使用诸如yepnope.js(我强烈建议)、head.js或require.js之类的方法,您还可以延迟加载任何遗留的javascript,从而获得巨大的感知加载时间。
我没有用document.write ,所以这很好。问题是,我想延迟加载外部代码,但内嵌代码依赖于它。使用此方法,我可以在正确的时间运行脚本。-)
我编辑了我的答案,以包含更好的方法。
我知道老问题(伟大的回答),但这可能有用。如果jquery也延迟了加载,并且您得到的时间错误与$是未定义的。在setinterval(var _si=setinterval…)中包装上述答案,并且仅在加载jquery时执行for循环。(如果是$的类型!="未定义")window.clearInterval(_si);for(var i=0,l=_scrip…)
您必须考虑将内联代码"移出"并将其包含在
1
< script defer= "defer" type= "text/javascript" src= "" >
defer="defer" 究竟做了什么?
@rocket:w3.org/tr/html4/interact/scripts.html adef defer
@罗奇:只要提供参考资料,你就得请回答者澄清:)
@rocket"所以,它使文件异步"—不,这是
HTML5为具有已定义src 的脚本引入了一个新的async 参数。
您可以直接添加到任何 元素上:
1
< script src= '/js/script.js' async>
但是:请记住,它不会在内联脚本上工作!
如果您的一些页面混合了外部脚本和内联脚本,如果您异步加载外部脚本,这意味着内联脚本实际上将在异步脚本之前执行…会产生不必要的影响。
Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously. It has no effect on inline scripts (i.e., scripts that don't have the src attribute).
例如,如果您有以下配置:
1 2 3 4 5 6 7
< script src= '/js/jquery.min.js' async>
// --> jQuery won't be loaded when this script will be executed!
// This will throw an error.
$( function ( ) {
$( '#element' ) .doSomething ( ) ;
} ) ;
首先,我建议您非常仔细地分析客户端上脚本的加载情况,不仅是第一次加载javascript,而且是第二次加载相同的javascript文件或将其加载到另一个页面时。如果Web服务器在脚本上正确设置了etag,或者如果您对javascripts文件使用HTTP的其他缓存选项(有关详细信息,请参阅缓存教程),则不会加载文件本身,只会执行缓存重新验证。所以你描述的问题可能不像它看起来那样重要。
如果您确实决定动态加载一些脚本,那么可以使用jquery.getscript并将所有相关代码放在success 回调中。如果您需要加载一个或两个javascript文件,这种方法将非常有效,但是如果您需要加载一个具有更复杂依赖关系的javascript文件列表,那么实现就不那么容易了。在这种情况下,您可以在 的内部使用document.writeln 。在 内部使用该方法几乎没有缺点(请参阅此处了解详细信息)。
我知道如何动态加载JavaScript。我的问题是我正在动态加载一个库,这个库在身体的某个地方使用。所以内联脚本失败,因为库不在那里。我想知道是否有一种快速的方法可以解决这个问题,而不需要将所有的javascript复制到他们自己的文件中。
@rocket:为什么你不能把使用库(内联脚本)的代码放在加载库的$.getScript 调用的success 句柄内?
我可以,但是有很多内联脚本标记。要做到这一点需要很长时间。我想知道我是否可以让浏览器自动为我做这件事。
@rocket:您必须在母版页或需要库的页中进行一些更改。从无到有。您准备好做哪些更改?
我只是想做尽可能小的改变。我想母版页会更容易些。
您可以在主页面中测试哪些信息,以验证它现在是否位于需要JavaScript库的页面中?你可以测试这些东西,如果需要,你可以用EDOCX1(包括库)调用document.writeln 。
你要我做什么?
哪些条件必须检测页面是否使用某些特定的库?你能在母版页内实现检测吗?
母版页知道它需要加载哪些库,这不是问题所在。问题是将内联代码延迟到这些操作完成为止。我可能只会将所有的内联代码移动到它们自己的文件中,但我只是在寻找解决方法。
@Rocket:你可以在这里看到,如果你执行document.writeln("
看看使用headjs。它是一个很好的轻量级库,可以为您完成所有这些工作。
我看过headjs,但问题是所有的内联javascript。我想找出一种方法来延迟主体中脚本标记的执行,直到库被加载。
您可以在注释中包装脚本标记的内容,然后regex匹配注释中的代码,然后在全局范围内对其进行eval:。
但是,如果它们是评论,我如何才能阅读它们呢?