可以推迟加载 jQuery 吗?

面对现实吧,jQuery/jQuery-ui 下载量很大。

Google 推荐使用 延迟加载 JavaScript来加速初始渲染。我的页面使用 jQuery 来设置一些放在页面下方的选项卡(大部分位于初始视图之外) ,我希望将 jQuery 推迟到页面呈现之后。

Google 的延迟代码在页面加载后,通过钩入 body onLoad 事件,向 DOM 添加了一个标记:

<script type="text/javascript">


// Add a script element as a child of the body
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "deferredfunctions.js";
document.body.appendChild(element);
}


// Check for browser support of event handling capability
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;


</script>

我希望以这种方式推迟加载 jQuery,但是当我尝试时,我的 jQuery 代码找不到 jQuery (对我来说并不完全出乎意料) :

$(document).ready(function() {
$("#tabs").tabs();
});

因此,我似乎需要找到一种方法,将 jQuery 代码的执行推迟到 jQuery 加载之后。如何检测添加的标记是否已完成加载和解析?

作为推论,似乎 异步加载也可能包含一个答案。

有什么想法吗?

68997 次浏览

将 jQuery 和与 jQuery 相关的代码放在 HTML 文件的末尾。

编辑: 更清楚一点

<html>
<head></head>
<body>
<!-- Your normal content here -->
<script type="text/javascript" src="http://path/to/jquery/jquery.min.js"></script>
<script>//Put your jQuery code here</script>
</body>
</html>

下面的代码应该在加载完窗口后加载脚本:

<html>
<head>
<script>
var jQueryLoaded = false;
function test() {
var myScript = document.createElement('script');
myScript.type = 'text/javascript';
myScript.async = true;
myScript.src = jQueryLoaded ? 'http://ajax.googleapis.com/ajax/libs/jquery/1.5.1/jquery.js' : 'http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js';
document.body.appendChild(myScript);


if(!jQueryLoaded){
alert('jquery was loaded');
jQueryLoaded = true;
test();
} else {
alert('jqueryui was loaded');
}
}


if (window.addEventListener){
alert('window.addEventListener');
window.addEventListener("load", test, false);
} else if (window.attachEvent){
alert('window.attachEvent');
window.attachEvent("onload", test);
} else{
alert('window.onload');
window.onload = test;
}
</script>
</head>
<body>
<p>Placeholder text goes here</p>
</body>
</html>

在 Chrome,FF 和 IE9中都很有用——如果有帮助请告诉我

在我看来,你所要做的就是: a)添加你想在加载时运行的 jQuery 代码,添加到 jQuery 文件的末尾,或者 b)像这样将它附加到 downloadJSAtOnload函数:

<script type="text/javascript">


// Add a script element as a child of the body
function downloadJSAtOnload() {
var element = document.createElement("script");
element.src = "deferredfunctions.js";
document.body.appendChild(element);
$("#tabs").tabs(); // <==== NOTE THIS. This should theoretically run after the
// script has been appended, though you'll have to test this
// because I don't know if the JavaScript above will wait for
// the script to load before continuing
}


// Check for browser support of event handling capability
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;


</script>
element.addEventListener("load", function () {
$('#tabs').tabs()
}, false);

试试这个。

试试这个,这是我不久前从 jQuerify bookmarklet 中编辑的内容。我经常使用它来加载 jQuery,并在加载后执行它。当然,您可以用您自己的 url 替换那里的 url 到您自定义的 jquery。

(function() {
  function getScript(url,success){
    var script=document.createElement('script');
    script.src=url;
    var head=document.getElementsByTagName('head')[0],
        done=false;
    script.onload=script.onreadystatechange = function(){
      if ( !done && (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete') ) {
        done=true;
        success();
        script.onload = script.onreadystatechange = null;
        head.removeChild(script);
      }
    };
    head.appendChild(script);
  }
getScript('http://ajax.googleapis.com/ajax/libs/jquery/1.5.2/jquery.min.js',function(){
// YOUR CODE GOES HERE AND IS EXECUTED AFTER JQUERY LOADS
});
})();

我会将 jQuery 和 jQuery-UI 合并到一个文件中,并使用一个指向该文件的 URL。如果您真的想分别加载它们,只需链接 getScripts:

getScript('http://myurltojquery.js',function(){
getScript('http://myurltojqueryUI.js',function(){
//your tab code here
})
});

看看 jQuery.holdReady()

“保存或释放 jQuery 的 ready 事件的执行”(jQuery 1.6 +)

Http://api.jquery.com/jquery.holdready/

下面是我的版本,它支持链接,以确保脚本一个接一个地加载,基于 & 符号的代码:

var deferredJSFiles = ['jquery/jquery', 'file1', 'file2', 'file3'];
function downloadJSAtOnload() {
if (!deferredJSFiles.length)
return;
var deferredJSFile = deferredJSFiles.shift();
var element = document.createElement('script');
element.src = deferredJSFile.indexOf('http') == 0 ? deferredJSFile : '/js/' + deferredJSFile + '.js';
element.onload = element.onreadystatechange = function() {
if (!this.readyState || this.readyState == 'loaded' || this.readyState == 'complete')
downloadJSAtOnload();
};
document.body.appendChild(element);
}
if (window.addEventListener)
window.addEventListener('load', downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent('onload', downloadJSAtOnload);
else
window.onload = downloadJSAtOnload;

由于这是一个重要问题的首要问题,让我大胆地根据@valmarv 和@amparand 先前的回答提出我自己的看法。

我使用一个多维数组来加载这些脚本,将那些没有依赖关系的脚本分组在一起:

var dfLoadStatus = 0;
var dfLoadFiles = [
["http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"],
["http://ajax.googleapis.com/ajax/libs/jqueryui/1.8.11/jquery-ui.min.js",
"/js/somespecial.js",
"/js/feedback-widget.js#2312195",
"/js/nohover.js"]
];


function downloadJSAtOnload() {
if (!dfLoadFiles.length) return;


var dfGroup = dfLoadFiles.shift();
dfLoadStatus = 0;


for(var i = 0; i<dfGroup.length; i++) {
dfLoadStatus++;
var element = document.createElement('script');
element.src = dfGroup[i];
element.onload = element.onreadystatechange = function() {
if ( ! this.readyState ||
this.readyState == 'complete') {
dfLoadStatus--;
if (dfLoadStatus==0) downloadJSAtOnload();
}
};
document.body.appendChild(element);
}


}


if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;

它在加载后首先加载 jquery,它继续同时加载其他脚本。您可以通过将脚本添加到页面上任何位置的数组中来轻松添加脚本:

dfLoadFiles.push(["/js/loadbeforeA.js"]);
dfLoadFiles.push(["/js/javascriptA.js", "/js/javascriptB.js"]);
dfLoadFiles.push(["/js/loadafterB.js"]);
<!doctype html>
<html>
<head>


</head>
<body>
<p>If you click on the "Hide" button, I will disappear.</p>
<button id="hide" >Hide</button>
<button id="show" >Show</button>


<script type="text/javascript">
function loadScript(url, callback) {


var script = document.createElement("script")
script.type = "text/javascript";


if (script.readyState) {  //IE
script.onreadystatechange = function() {
if (script.readyState == "loaded" ||
script.readyState == "complete") {
script.onreadystatechange = null;
callback();
}
};
} else {  //Others
script.onload = function() {
callback();
};
}


script.src = url;
document.body.appendChild(script);
}
loadScript("http://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js",
function() {
//YAHOO.namespace("mystuff");
$("#show").click(function() {
$("p").show();
});
$("#hide").click(function() {
$("p").hide();
});


//more...
});
</script>


</body>
</html>

在某些情况下,您可以在加载 jquery 时触发一个事件。

<script type="text/javascript">
(function (window) {


window.jQueryHasLoaded = false;


document.body.addEventListener('jqueryloaded', function (e) {
console.log('jqueryloaded ' + new Date() );
}, false);


function appendScript(script) {
var tagS = document.createElement("script"),
s = document.getElementsByTagName("script")[0];
tagS.src = script.src;
s.parentNode.insertBefore(tagS, s);


if ( script.id == 'jquery' ) {
tagS.addEventListener('load', function (e) {
window.jQueryHasLoaded = true;
var jQueryLoaded = new Event('jqueryloaded');
document.body.dispatchEvent(jQueryLoaded);
}, false);
}
}


var scripts = [
{
'id': 'jquery',
'src': 'js/libs/jquery/jquery-2.0.3.min.js'
},
{
'src': 'js/myscript1.js'
},
{
'src': 'js/myscript2.js'
}
];


for (var i=0; i < scripts.length; i++) {
appendScript(scripts[i]);
}


}(window));
</script>

然后将依赖项包装在一个函数中:

// myscript1.js
(function(){


function initMyjQueryDependency() {
console.log('my code is executed after jquery is loaded!');
// here my code that depends on jquery
}


if ( jQueryHasLoaded === true )
initMyjQueryDependency();
else
document.body.addEventListener('jqueryloaded', initMyjQueryDependency, false);


}());

如果 jquery 在其他脚本之后完成加载,那么在触发 jqueryload 事件时将执行您的依赖项。

如果已经加载了 jquery,则将执行依赖关系 initMyjQueryDependency()

http://labjs.com加载 html 末尾的所有脚本,这是100% 的解决方案,我根据 gtmetrix 规则对它进行了多次测试。例子 http://gtmetrix.com/reports/interactio.cz/jxomHSLV

我认为在这里值得一提-它可以很好地处理依赖性加载

我将这段代码添加到了异步/延迟 jquery 脚本标记之后,它定义了一个临时函数 $,该函数将积累所有在加载完成后需要运行的内容,然后一旦我们完成使用 $,该函数将被覆盖以执行这些函数。有了这段代码,就不需要在文档中进一步更改 jQuery onload 语法。

<script defer async src="https://code.jquery.com/jquery-2.2.0.min.js">
<script>
var executeLater = [];
function $(func) {
executeLater.push(func);
}
window.addEventListener('load', function () {
$(function () {
for (var c = 0; c < executeLater.length; c++) {
executeLater[c]();
}
});
})
</script>

然后..。

<script>
$(function() {
alert("loaded");
});
</script>

下面是对 异步/延迟 javascript 加载的现代方法的一个很好的描述,但是它不适用于内联脚本

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script>
<script type="text/javascript" defer>
$(function () {   //  <- jquery is not yet initialized
...
});
</script>

最简单的异步加载解决方案是@nilskp-exteralize 脚本提出的:

<script type="text/javascript" src="/jquery/3.1.1-1/jquery.min.js" defer></script>
<script type="text/javascript" src="resources/js/onload.js" defer></script>

谷歌分析使用了一个简单的技巧。

准备工作

在 HTML 的头部添加一个小脚本

<script>
window.jQuery_store = [];
window.jQueryReady = function (fn) { jQuery_store.push(fn); }
</script>

函数 jQueryReady 只是将委托保存到一个数组中以备将来使用。

2. 创建一个新的 JS 脚本 jquery-ready.js,包含以下内容:

// When jQuery is finaly ready
$(function() {
// Replace previous implementation
window.jQueryReady = function(fn) {
// jQuery is loaded call immediately
fn();
}
    

// Call all saved callbacks
for (var i = 0; i < window.jQuery_store.length; ++i) {
try {
window.jQuery_store[i]();
} catch (err) {
console.log(err);
}
}
})

当加载这个脚本时,它将:

  • 等到 jQuery可以安全使用
  • 将用一个新的函数替换函数 jQueryReady,该函数将立即调用委托(jQuery 在给定时间就绪)。
  • 迭代从以前的 jQueryReady调用中保存的函数。

把所有东西放在一起 只有在加载 jQuery 之后才加载 jQuery-ready. js。 在你的页脚,你会有:

<script defer src=".../jquery.min.js">
<script defer src=".../bootstrap.min.js">
... any other plugins for jQuery you probably need
<script defer src=".../jquery-ready.js">

这样可以确保 jQuery-ready. js 脚本只在 jQuery 执行之后执行。

用法

现在可以随时使用 jQueryReady 函数。

jQueryReady(function() {
// jQuery is safe to use here
$("div.to-be-hidden").hide();
})

我想在 WordPress 网站上推迟加载 jQuery,所以实际上我不能使用它来更新所有的引用。 相反,我们编写了一个小包装器来对 jQuery 调用进行排队,然后在最终加载它时调用它。 把它放在头部,只有250字节左右,这意味着 jQuery 可以被延迟或异步加载,而不需要改变所有现有的引用。让我的装载时间变得更好。

我的快速代码可能不适用于所有 jQuery 函数,但到目前为止,除了一个函数调用之外,所有函数都能正常工作。 通常我做这样的定制的东西,我不让它可用,但我想我把这个片段放在网上。可在这里下载 < a href = “ https://github.com/andrewtranter/jQuery _ 团队延迟 _ compat”rel = “ nofollow norefrer”> https://github.com/andrewtranter/jquery_deferred_compat