0

I have seen the following code in a JavaScript tutorial:

function loadScript(src) {
  // creates a <script> tag and append it to the page
  // this causes the script with given src to start loading and run when complete
  let script = document.createElement('script');
  script.src = src;
  document.head.append(script);
}

loadScript('/my/script.js');
// the code below loadScript
// doesn't wait for the script loading to finish
// ...

The comment says:

The script is executed “asynchronously”, as it starts loading now, but runs later, when the function has already finished.

  1. Why is this script executed asynchronously? What inside or outside the function loadScript makes the code execute asynchronously?

The following code uses a corrected version of the function defined above, that takes into account the synchronization with dependent code:

function loadScript(src, callback) {
  let script = document.createElement('script');
  script.src = src;
  script.onload = () => callback(script);
  document.head.append(script);
}

loadScript('https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js', script => {
  alert(`Cool, the script ${script.src} is loaded`);
  alert( _ ); // function declared in the loaded script
});
  1. What does the underscore in the alert call mean?

  2. Why does it alert the first function in the loaded script?

  3. Is this the only way to do the synchronization? I would not call it a clean design because it ties two separate functions just because of how they may be called.

rapt
  • 11,810
  • 35
  • 103
  • 145
  • 2. `_` is a global variable declared by the lodash library. – Jonas Wilms Aug 28 '21 at 21:35
  • 1. The network. You don't want to block execution while loading a new script from the server (which takes quite a few milliseconds) – Jonas Wilms Aug 28 '21 at 21:36
  • For what it's worth, one rarely manually loads further scripts. Instead one would use multiple ` – Jonas Wilms Aug 28 '21 at 21:39
  • @JonasWilms 2. "a global variable" whose value is what? 1. "The network" - but which part of the code is asynchronous? The fact that an operation takes a long time does not by itself mean that it's asynchronous... it might mean that you want to make it asynchronous. – rapt Aug 29 '21 at 08:33
  • `script.src =` as it starts loading the script, though does not wait for it to finish – Jonas Wilms Aug 29 '21 at 11:28

1 Answers1

0
  1. The callback is not called directly, it is executed after the script file was loaded.

The onload or onerror will never trigger directly (syncronous). It will be execute after the main thread has finished the current call. Even if the script is cached or loaded from a local resource, it will be delayed and only executed after the main thread has finished the last call.

An example of this behavior would be:

function doSomething() {
  setTimeout(() => { console.log("Hello World"); }, 0);
  console.log("Hello you!");
  // freeze the thread for 1s?
  const start = Date.now();
  while (Date.now()-start < 1000); // blocked
  console.log("You still there?");
}
doSomething();

No matter how long the script takes, the timeout is called after the function call (asyncronous). Even if the timeout has a 0ms delay and "should" be executed directly, the "Hello you!" and "You still there?" is returned first.

Asyncrounous?

Normally, a given program's code runs straight along, with only one thing happening at once. If a function relies on the result of another function, it has to wait for the other function to finish and return, and until that happens, the entire program is essentially stopped from the perspective of the user.

JavaScript works on a single thread.

  1. The alert( _ ) is a proof, that lodash is defined at the global object. (Check the last lines of https://cdnjs.cloudflare.com/ajax/libs/lodash.js/3.2.0/lodash.js -- it defines _ at the global object.)

    If you want an explaination what lodash is and what it does, take a look at it's website. -- It provides lots of useful functions.

  2. The onload passes the script tag created to the callback routine.

      script.onload = () => callback(script);
    

    After the onload event is fired, the loadash file was executed without an error and is available at the global object. This will be converted to a string and displayed, if possible. For a better explaination of, how the javascript closures work, take a look at this answer.

  3. No it's not. You can make use of Promises.

    function loadScript(src) {
      return new Promise((resolve, reject) => {
        let script = document.createElement('script');
        script.src = src;
        script.onload = () => resolve(script);
        script.onerror = (error) => reject(error);
        document.head.append(script);
      })
    }
    

    Now you can use:

    loadScript('uri...')
      .then(script => { console.log(`${script.src} was loaded`) })
      .catch(error => {
        console.error(error);
      })
    

    Or inside an async function you can use it like this:

    async function whatever() {
      try {
        const scriptLoaded = await loadScript('url...');
        // code to execute, after the file was loaded
      } catch (err) {
        console.error(err);
      }
    }
    
Christopher
  • 3,124
  • 2
  • 12
  • 29
  • 1. It doesn't answer the question... 2. But what does _ mean... what is its value? 3. But the question is why _ means the first function in the loaded script... – rapt Aug 29 '21 at 02:26
  • I updated it. You should consider asking one question, not four at once. Please take a look at [this post](https://meta.stackexchange.com/a/222741/814547). – Christopher Aug 29 '21 at 11:51