简体   繁体   中英

Lazy loading JavaScript and Inline JavaScript

I noticed in the <head> of my site (for work), there are a lot of <link rel="stylesheet" type="text/css" href="" /> and <script type="text/javascript" src=""> tags. There are even more JavaScript/CSS files that are only loaded for specific pages (we're using CodeIgniter, and the file paths are passed to the header view).

I was considering using a conditional/asynchronous loader (eg. yepnope.js, head.js, etc.), but I noticed a small problem with doing this.

In our views, there is inline JavaScript, some uses $(function(){}) some uses $(document).ready(function(){}) , and some just has code (using jQuery) that's not in a ready block.

Without editing EVERY view file to wrap its code in a function and calling that when the JS files are loaded, is there a way to delay the inline code until the JavaScript is asynchronously loaded?

You can actually lazyload inline javascript: 1- Change the type parameter in the inline script to: text/delayscript

FROM

    <!– Inline Script –>
<script type="text/javascript" language="javaScript">
             /* Code */
</script>

To

    <!– Inline Script –>
<script type="text/delayscript">
             /* Code */
</script>

Giving the script tag a custom Mime type text/delayscript forces the browser to ignore its content (Please note that leaving it out entirely will default to text/javascript).

2- Lazy load all inline scripts Once heads.js (Or an other framework you might be using) confirms that it lazy loaded all your external JS, you can then grab the content of all your custom script tags and inject them in the page:

<script>
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);

});

To be even more graceful, you can actually keep the inline scripts in their original hierarchy in the DOM tree instead of jamming all their content in one script, as I have suggested above, by replacing the marked inline script tag by a new one that has mime type text/javascript:

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]);
}
});

您必须考虑将内联代码移到“外部”并将其包含在

<script defer="defer" type="text/javascript" src="">

HTML5 introduced a new async parameter for scripts having a defined src .

You can add it directly on any <script> element :

<script src='/js/script.js' async></script>

BUT : keep in mind that it will not work on inline scripts!

And if your some of your pages mix either external and inline scripts, if you load the external asynchronously, it means that the inline scripts will actually be executed before the asynchronous ones... Which can have unwanted effects.

Set this Boolean attribute to indicate that the browser should, if possible, execute the script asynchronously. It has no effect on inline scripts (ie, scripts that don't have the src attribute).

For instance, if you have the following configuration :

<script src='/js/jquery.min.js' async></script>
<script>
    // --> jQuery won't be loaded when this script will be executed!
    // This will throw an error.
    $(function () {
        $('#element').doSomething();
    });
</script>

First of all I would recommend you to analyse the loading of the scripts on the client side very carefully and not only for the first JavaScript loading, but on the loading of the same JavaScript files at the second time or its loading on another page. If the ETag are correctly set on the scripts by the web server or if you use other caching options of HTTP (see the caching tutorial for details) for the JavaScripts files than no loading of the files itself will take place and only the cache revalidation will be done. So it can be that the problem which you describes is not so important like it looks like.

If you do decide to load some scripts dynamically you can use jQuery.getScript and place all dependent code inside of the success callback. If you need to load one or two JavaScript files the way will work very good, but if you need to load a list of JavaScript files with more complex dependency the implementation could be not so easy. In the case you can use document.writeln inside of <head> . The usage of the method inside of <head> has almost no disadvantages (see here for details).

Depending on your setup, you might want to look into the service from www.cloudflare.com. Their current beta functionality called rocket loader, does exactly that, including the inline scripts.

It's a free service. try it out ;)

Plus you get a free caching proxy on top :)

Instead of inline scripts, create inline functions. Then at the end of your javascript file, call the function if it exists.

function inline_script() {.. code ..}

Inside your concatenated jquery+etc async javascript file:

if (typeof(inline_script) == 'function') inline_script()

You'll have to do some shuffling to make sure you only have one inline_script per page, or use some kind of caching to put them together if you call it more than once.

It's still a fun problem in the current age even though this question is old, async scripts = pretty awesome

Have a look at using headjs . It is a nice lightweight library that will do this all for you.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM