Asynchronous Javascript Loaders

I’d like to take advantage of loading my scripts while the page is loading. ie. Yepnope, head.js etc…

But I also want to be able to enqueue the script so other plugins don’t try adding their own. (a la jquery)

Read More

Does anyone have any suggestions?

Thanks in advance…

Related posts

Leave a Reply

5 comments

  1. You can’t have both: you either use wp_enqueue_script() or head.js

    Or, you do some wacky hacking to translate the WP script dependency tree into head.js calls.

    NB: Replace head.js with whatever library you want to use.

  2. This should be a comment, but I don’t have those privilages yet.

    But if primary concern is just to prevent duplication, deregister the script, then register the same script with no source and enqueue it. Essentially, wp will run a blank script to block every other register/enqueue version of it.

    Then add the script with the method of your choice. I haven’t done thorough testing, but got the tip from somewhere else, and in theory it should work fine.

  3. Here’s what I’m doing to accomplish this. I’m posting this as a possible solution, and also to get feedback from anyone with more WP experience than me. If you see any problems with my implementation or anything I’m not considering, please let me know.

    Known limitations:

    • It only works with scripts that are properly enqueued via wp_enqueue_script
    • It outputs all scripts in the footer even if they were registered to only be output in the <head> section of the page. This might be easy to work around, but for my implementation I prefer it this way.

    The problem I saw with the head.js plugin was that it only seemed to work on scripts in the <head> section, and the fact that it didn’t allow for any easy CDN fallback functionality which is a really nice benefit of loading scripts this way in my opinion.

    Ok, here’s the code. This is part of a class that is in my general functionality plugin, but it could just as easily be in functions.php or organized in some other way. I’m using yepnope for now, but this could easily be modified to use another script loader.

    class example {
    
        function __construct() {
    
            /*
            Hook into the script printing functionality and use our own resource loader to load
            scripts in a non-blocking, asynchronous, parallel fancy way
            */
            if( !is_admin() ) {
    
                add_action( 'wp_print_scripts',  array( &$this, 'deploy_script_loader' ) );
            }       
        }   
    
        /*
        If we have any javascripts queued for the page, grab the handles of
        all of the ones to be loaded in the header and dequeue them now. 
        Then, we will check again and reload any that weren't queued
        yet in the footer.
        */
        function deploy_script_loader( ) {
            global $wp_scripts;
    
            if ( !empty( $wp_scripts->queue ) && !is_admin() ) {
    
                // Get the queue in our class property, and dequeue everything
                foreach ( $wp_scripts->queue as $handle ) {
    
                    /*
                    Check if this script is supposed to be loaded in the header (group isn't 1).
                    If it is, we'll grab it now and dequeue it. We'll save the rest of the dequeuing
                    for the footer script or else we'll miss some scripts that are queued after
                    this hook is run.
                    */
                    if ( 1 !== $wp_scripts->registered[$handle]->extra['group'] ) {
    
                        /*
                        Just dequeuing a script here isn't enough to prevent it from being
                        printed in the header if another script that we haven't dequeued (ie a footer
                        script) depends on it. So, we need to make sure that all of the
                        scripts we just dequeued will be ok loading in the footer (where they will
                        get dequeued for real before they are printed).
                        */
                        $wp_scripts->registered[$handle]->extra['group'] = 1;
                    }
                }
    
                // Add our hook to load everything in the footer
                add_action( 'wp_footer', array( &$this, 'output_script_loader' ) );
            }       
        }
    
        /*
        Function to be ran in wp_footer to output the js script loader
        html content.
        */
        function output_script_loader() {
            global $wp_scripts;
    
        // Process the scripts dependency tree, but don't print anything
        ob_start();
        $script_queue = $wp_scripts->do_items();
        ob_clean();
    
            // Add our script loader
            echo '<script type="text/javascript" src="' . plugins_url( '/scripts/yepnope.1.0.2-min.js', __FILE__ ) . '"></script><script type="text/javascript">';
    
            // Loop through the queued scripts and get all of their localization output objects first
            foreach( $script_queue as $handle ) {
    
                echo $wp_scripts->registered[$handle]->extra['data'];
            }
    
            echo 'yepnope.errorTimeout = 4000; yepnope([';
    
            $i = 0;
            $count = count( $script_queue );
    
            // Loop through the queued scripts again, this time output the script loader syntax
            foreach( $script_queue as $handle ) {
    
                if ( 'jquery' === $handle ) {
    
                    $jquery_cdn_url = ( is_ssl() ) ? 'https://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js' : 'http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js';
    
                    echo ' { load: "'. $jquery_cdn_url .'", callback: function () { if (!window.jQuery) { yepnope("' . $wp_scripts->base_url . $wp_scripts->registered['jquery']->src . '"); } } },';
                } else {
    
                    $src = $wp_scripts->registered[$handle]->src;
    
                    // Check if this is a relative path or if we have the whole thing
                    if( 'http' !== strtolower( substr( $src, 0, 4 ) ) ) {
    
                        $src = $wp_scripts->base_url . $src;
                    } else {
    
                        $src = ( is_ssl() ) ? 'https' . substr( $src, strpos( $src, ':' ), strlen( $src ) ) : 'http' . substr( $src, strpos( $src, ':' ), strlen( $src ) );
                    }
    
                    $comma = ( $i == ( $count - 1 ) ) ? '' : ',';
    
                    echo '{ load: "' . $src . '" }' . $comma;
                }
    
                $i++;
            }       
    
            echo ']);</script>';
        }
    }
    
    // Instantiate the class
    new example;
    
  4. Here is the easy way for adding asynchronous to all custom js files in WordPress.

    Add in functions.php :

    // Async load for all style
        function base_async_scripts($url)
        {
            if ( strpos( $url, '#asyncload') === false )
                return $url;
            else if ( is_admin() )
                return str_replace( '#asyncload', '', $url );
            else
            return str_replace( '#asyncload', '', $url )."' async='async"; 
            }
        add_filter( 'clean_url', 'base_async_scripts', 11, 1 );
    
    //add or change in url as mentioned below
    wp_enqueue_script( 'base-functions', get_template_directory_uri() . '/js/functions.js#asyncload', array( 'jquery' ), null, true );