I'm looking to optimise the way in which larger javascript files are loaded in my MVC project. I'm already using bundling and minification but I would really like to only load a few of them AFTER the the HTML and CSS are loaded. I was looking at this kind of approach:
https://varvy.com/pagespeed/defer-loading-javascript.html
In this approach the script tags are injected into using javascript in the load/onload event after the body is loaded. My problem is that I would like to use along side the bundling and minification offered by the framework and I haven't found a good way to do that.
I'l just wondering if anybody has successfully used this approach with MVC projects and if there might already be a library (on Nuget or otherwise) to facilitate this.
EDITED: Here is my current solution, but I'm not sure I like it.
Since the Bundling framework can return a single script tag or a list of them depending on whether you're running in debug or not we need to extract the source values for those tags. To do this I created a static helper.
public static string ExtactFromScriptBundle(string aBundle)
{
List<string> returnValue = new List<string>();
var jQueryString = Scripts.Render(aBundle).ToHtmlString();
var reg = new Regex("\".*?\"");
var matches = reg.Matches(jQueryString);
foreach (var match in matches)
{
returnValue.Add(match.ToString().Replace("\"", ""));
}
return Json.Encode(returnValue);
}
Than from _layout.cshtml you cound insert a block like the following right before the tag:
<script>
function downloadJSAtOnload() {
createScripElementsFromArray(@Html.Raw(ScriptHelper.ExtactFromScriptBundle("~/bundles/jquery")));
createScripElementsFromArray(@Html.Raw(ScriptHelper.ExtactFromScriptBundle("~/bundles/bootstrap")));
}
function createScripElementsFromArray(fileNameList) {
var arrayLength = fileNameList.length;
for (var i = 0; i < arrayLength; i++) {
createScripElement(fileNameList[i]);
}
}
function createScripElement(fileName) {
var element = document.createElement("script");
element.src = fileName;
document.body.appendChild(element);
console.log(fileName + " was loaded");
}
if (window.addEventListener)
window.addEventListener("load", downloadJSAtOnload, false);
else if (window.attachEvent)
window.attachEvent("onload", downloadJSAtOnload);
else window.onload = downloadJSAtOnload;
</script>
It's a bit a hack in my opinion since I'm rendering the bundles just to parse the output, but I guess I could also cache those outputs to further optimize the page rendering.
By Occam's Razor , the best solution is to use the defer attribute ...
<script src='myJavaScriptFile.js' defer></script>
It is well supported .
If you want to use it in ASP.NET MVC, then you'll do this:
Create a new Razor command like so:
public static class Scripts
{
public static IHtmlString RenderDeferred(params string[] paths)
{
return Scripts.RenderFormat(@"<script src='{0}' defer></script>", paths);
}
}
And then use it like this:
@Scripts.RenderDeferred("~/myBundle/myJavaScriptBundle")
One option is to use jquery to load external scripts. You'd have an initial dependency on jquery itself but jquery is very light weight.
You'd then have:
$(document).ready(function(){
//At this point, the HTML/CSS has already been loaded and rendered.
//load external scripts
$.getScript( "ajax/test.js", function( data, textStatus, jqxhr ) {
console.log( data ); // Data returned
console.log( textStatus ); // Success
console.log( jqxhr.status ); // 200
console.log( "Load was performed." );
});
});
Jquery doc: https://api.jquery.com/jquery.getscript/
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.