问题
为了提高页面的表现,我需要预装 ,我需要在底部网页上运行 的脚本 。
我想借此当脚本解析,编译和执行的控制。
我必须避免script标签 ,因为它是阻断共同渲染引擎 (geeko等)。
它使用延迟属性,因为我需要的是执行脚本时要控制,我可以不加载。 此外, 异步属性的可能性也不大。
样品:
<html><head>
//preload scripts ie: a.js without use the script
</head><body> ..... all my nice html here
//execute here a.js
</body></html>
这使我能够最大限度地呈现在我的网页的性能,因为浏览器将开始donwload脚本内容,它会在同时并行渲染页面。 最后,我可以添加脚本标记,因此浏览器将解析,编译和执行代码。
我能做到这一点的唯一方法是使用一个隐藏的图像标记。 (这是一个简化斯托的版本 )
即
<html><head>
<img src="a.js" style=display:none;>
</head><body> ..... all my nice html here
<script src="a.js">
</body></html>
题
我没有发现使用这种技术的任何问题,但没有人知道一个更好的方式来做到这一点? 是否有任何元预取?
附加信息
我使用requirejs,所以我想预加载模块的代码,而不执行它,因为这段代码取决于DOM元素。
你应该看看下面的链接:
http://calendar.perfplanet.com/2011/lazy-evaluation-of-commonjs-modules/
http://tomdale.net/2012/01/amd-is-not-the-answer/
而在ember.js如何使用一个工具,称为minispade与红宝石预处理,使加载过程,解析和运行的JavaScript模块快。
随着类似的技术可能会使用预加载脚本和样式表img
的Internet Explorer和object
标记为其他浏览器。
var isMSIE = /*@cc_on!@*/false;
var resources = ['a.js', 'b.js', 'c.css'];
for (var i=0; i<resources.length; i++){
if (isMSIE){
new Image().src = resources[i];
} else {
var o = document.createElement('object');
o.data = resources[i];
document.body.appendChild(o);
}
}
有一个博客帖子描述了这样的技术,并概述警告: 不执行预加载CSS / JavaScript的 。
但是,为什么你不希望只使用动态添加脚本仿如建议在其他的答案,这或许将导致更多的控制一个清晰的解决方案。
您可以使用prefetch
的链接标签的属性来预加载任何资源,包括JavaScript的。 在撰写本文时(2016年8月10日),它不是在Safari浏览器的支持,但几乎其他任何地方:
<link rel="prefetch" href="(url)">
上支持更多资讯: http://caniuse.com/#search=prefetch
需要注意的是IE 9,10未在上市caniuse
矩阵,因为微软已经停止对他们的支持。
更多资讯 ,并为预加载更多的选择,如预渲染和更
对于每一个脚本,你想下载而不执行,使包含名称和URL的对象,并把这些对象到一个数组。
循环遍历数组,使用jQuery.ajax
与dataType: "text"
下载脚本为文本。 在done
Ajax调用的处理程序,将文件存储在适当的对象(在第一个参数传递)的文本内容,增加一个计数器,并称之为一个“alldone”功能,当该计数器等于文件数您正在下载这种方式。
在“alldone”功能(或更高版本)执行以下操作:依次通过您的阵列再次,对于每个条目,使用document.createElement("script")
document.createTextNode(...)
和(...scriptNode...).appendChild(...)
来动态产生具有,而不是通过“src”属性的预期源内嵌脚本。 最后,做document.head.appendChild(...scriptNode...)
则执行该脚本时,这是一点。
我曾经在一个项目中,我需要使用框架,几个帧和/或该框架需要相同的JavaScript文件,以确保每个这些文件的请求从服务器只能使用一次这种技术。
代码(测试和工作)如下
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
<html>
<head>
<script id="scriptData">
var scriptData = [
{ name: "foo" , url: "path/to/foo" },
{ name: "bar" , url: "path/to/bar" }
];
</script>
<script id="scriptLoader">
var LOADER = {
loadedCount: 0,
toBeLoadedCount: 0,
load_jQuery: function (){
var jqNode = document.createElement("script");
jqNode.setAttribute("src", "/path/to/jquery");
jqNode.setAttribute("onload", "LOADER.loadScripts();");
jqNode.setAttribute("id", "jquery");
document.head.appendChild(jqNode);
},
loadScripts: function (){
var scriptDataLookup = this.scriptDataLookup = {};
var scriptNodes = this.scriptNodes = {};
var scriptNodesArr = this.scriptNodesArr = [];
for (var j=0; j<scriptData.length; j++){
var theEntry = scriptData[j];
scriptDataLookup[theEntry.name] = theEntry;
}
//console.log(JSON.stringify(scriptDataLookup, null, 4));
for (var i=0; i<scriptData.length; i++){
var entry = scriptData[i];
var name = entry.name;
var theURL = entry.url;
this.toBeLoadedCount++;
var node = document.createElement("script");
node.setAttribute("id", name);
scriptNodes[name] = node;
scriptNodesArr.push(node);
jQuery.ajax({
method : "GET",
url : theURL,
dataType : "text"
}).done(this.makeHandler(name, node)).fail(this.makeFailHandler(name, node));
}
},
makeFailHandler: function(name, node){
var THIS = this;
return function(xhr, errorName, errorMessage){
console.log(name, "FAIL");
console.log(xhr);
console.log(errorName);
console.log(errorMessage);
debugger;
}
},
makeHandler: function(name, node){
var THIS = this;
return function (fileContents, status, xhr){
THIS.loadedCount++;
//console.log("loaded", name, "content length", fileContents.length, "status", status);
//console.log("loaded:", THIS.loadedCount, "/", THIS.toBeLoadedCount);
THIS.scriptDataLookup[name].fileContents = fileContents;
if (THIS.loadedCount >= THIS.toBeLoadedCount){
THIS.allScriptsLoaded();
}
}
},
allScriptsLoaded: function(){
for (var i=0; i<this.scriptNodesArr.length; i++){
var scriptNode = this.scriptNodesArr[i];
var name = scriptNode.id;
var data = this.scriptDataLookup[name];
var fileContents = data.fileContents;
var textNode = document.createTextNode(fileContents);
scriptNode.appendChild(textNode);
document.head.appendChild(scriptNode); // execution is here
//console.log(scriptNode);
}
// call code to make the frames here
}
};
</script>
</head>
<frameset rows="200pixels,*" onload="LOADER.load_jQuery();">
<frame src="about:blank"></frame>
<frame src="about:blank"></frame>
</frameset>
</html>
其他问题密切相关,上述方法等相关问题
为什么不试试呢?
var script = document.createElement('script');
script.src = 'http://path/to/your/script.js';
script.onload = function() {
// do something here
}
document.head.appendChild(script);
你可以使用.onload事件时加载控制。 一个需要注意的是,.onload()不能在IE浏览器,你可以使用这个:
script.onreadystatechange = function() {
if (/^loaded|complete$/i.test(this.readyState)) {
// loaded
};
}
通过DOM另外添加脚本是非阻塞的,我相信你可以完美实现这种方法你的目标。
我已经回答有同样的问题:
https://stackoverflow.com/a/46121439/1951947
只是使用<link>
标签来预加载您的脚本,然后你可以用用它<script>
标记
例如: <link href="/js/script-to-preload.js" rel="preload" as="script">