load scripts asynchronously

前端 未结 19 1045
粉色の甜心
粉色の甜心 2020-11-22 12:01

I am using several plugins, custom widgets and some other libraries from JQuery. as a result I have several .js and .css files. I need to create a loader for my site because

相关标签:
19条回答
  • 2020-11-22 12:20

    Well, x.parentNode returns the HEAD element, so you are inserting the script just before the head tag. Maybe that's the problem.

    Try x.parentNode.appendChild() instead.

    0 讨论(0)
  • 2020-11-22 12:21

    Here a little ES6 function if somebody wants to use it in React for example

    import {uniqueId} from 'lodash' // optional
    /**
     * @param {String} file The path of the file you want to load.
     * @param {Function} callback (optional) The function to call when the script loads.
     * @param {String} id (optional) The unique id of the file you want to load.
     */
    export const loadAsyncScript = (file, callback, id) => {
      const d = document
      if (!id) { id = uniqueId('async_script') } // optional
      if (!d.getElementById(id)) {
        const tag = 'script'
        let newScript = d.createElement(tag)
        let firstScript = d.getElementsByTagName(tag)[0]
        newScript.id = id
        newScript.async = true
        newScript.src = file
        if (callback) {
          // IE support
          newScript.onreadystatechange = () => {
            if (newScript.readyState === 'loaded' || newScript.readyState === 'complete') {
              newScript.onreadystatechange = null
              callback(file)
            }
          }
          // Other (non-IE) browsers support
          newScript.onload = () => {
            callback(file)
          }
        }
        firstScript.parentNode.insertBefore(newScript, firstScript)
      } else {
        console.error(`The script with id ${id} is already loaded`)
      }
    }

    0 讨论(0)
  • 2020-11-22 12:25

    Here is a great contemporary solution to the asynchronous script loading though it only address the js script with async false.

    There is a great article written in www.html5rocks.com - Deep dive into the murky waters of script loading .

    After considering many possible solutions, the author concluded that adding js scripts to the end of body element is the best possible way to avoid blocking page rendering by js scripts.

    In the mean time, the author added another good alternate solution for those people who are desperate to load and execute scripts asynchronously.

    Considering you've four scripts named script1.js, script2.js, script3.js, script4.js then you can do it with applying async = false:

    [
      'script1.js',
      'script2.js',
      'script3.js',
      'script4.js'
    ].forEach(function(src) {
      var script = document.createElement('script');
      script.src = src;
      script.async = false;
      document.head.appendChild(script);
    });
    

    Now, Spec says: Download together, execute in order as soon as all download.

    Firefox < 3.6, Opera says: I have no idea what this “async” thing is, but it just so happens I execute scripts added via JS in the order they’re added.

    Safari 5.0 says: I understand “async”, but don’t understand setting it to “false” with JS. I’ll execute your scripts as soon as they land, in whatever order.

    IE < 10 says: No idea about “async”, but there is a workaround using “onreadystatechange”.

    Everything else says: I’m your friend, we’re going to do this by the book.

    Now, the full code with IE < 10 workaround:

    var scripts = [
      'script1.js',
      'script2.js',
      'script3.js',
      'script4.js'
    ];
    var src;
    var script;
    var pendingScripts = [];
    var firstScript = document.scripts[0];
    
    // Watch scripts load in IE
    function stateChange() {
      // Execute as many scripts in order as we can
      var pendingScript;
      while (pendingScripts[0] && ( pendingScripts[0].readyState == 'loaded' || pendingScripts[0].readyState == 'complete' ) ) {
        pendingScript = pendingScripts.shift();
        // avoid future loading events from this script (eg, if src changes)
        pendingScript.onreadystatechange = null;
        // can't just appendChild, old IE bug if element isn't closed
        firstScript.parentNode.insertBefore(pendingScript, firstScript);
      }
    }
    
    // loop through our script urls
    while (src = scripts.shift()) {
      if ('async' in firstScript) { // modern browsers
        script = document.createElement('script');
        script.async = false;
        script.src = src;
        document.head.appendChild(script);
      }
      else if (firstScript.readyState) { // IE<10
        // create a script and add it to our todo pile
        script = document.createElement('script');
        pendingScripts.push(script);
        // listen for state changes
        script.onreadystatechange = stateChange;
        // must set src AFTER adding onreadystatechange listener
        // else we’ll miss the loaded event for cached scripts
        script.src = src;
      }
      else { // fall back to defer
        document.write('<script src="' + src + '" defer></'+'script>');
      }
    }
    
    0 讨论(0)
  • 2020-11-22 12:28

    One reason why your scripts could be loading so slowly is if you were running all of your scripts while loading the page, like this:

    callMyFunctions();
    

    instead of:

    $(window).load(function() {
          callMyFunctions();
    });
    

    This second bit of script waits until the browser has completely loaded all of your Javascript code before it starts executing any of your scripts, making it appear to the user that the page has loaded faster.

    If you're looking to enhance the user's experience by decreasing the loading time, I wouldn't go for the "loading screen" option. In my opinion that would be much more annoying than just having the page load more slowly.

    0 讨论(0)
  • 2020-11-22 12:28

    Have you considered using Fetch Injection? I rolled an open source library called fetch-inject to handle cases like these. Here's what your loader might look like using the lib:

    fetcInject([
      'js/jquery-1.6.2.min.js',
      'js/marquee.js',
      'css/marquee.css',
      'css/custom-theme/jquery-ui-1.8.16.custom.css',
      'css/main.css'
    ]).then(() => {
      'js/jquery-ui-1.8.16.custom.min.js',
      'js/farinspace/jquery.imgpreload.min.js'
    })
    

    For backwards compatibility leverage feature detection and fall-back to XHR Injection or Script DOM Elements, or simply inline the tags into the page using document.write.

    0 讨论(0)
  • 2020-11-22 12:28

    I would suggest looking into minifying the files first and see if that gives you a big enough speed boost. If your host is slow, could try putting that static content on a CDN.

    0 讨论(0)
提交回复
热议问题