DEV Community

loading...

Multithreading in JavaScript, sort of

aminnairi profile image Amin Updated on ・2 min read

I'm just kidding. JavaScript is single threaded, and I wont use Web Workers here. This was a clickbait. Sorry...

But wait, come back!

What I'll show you is a real game changer for people seeking a solution to lighten the script load on their page. It even works for those of you who don't want to/can't use a web server.

The source-code

<!DOCTYPE html>
<html>
  <body>
    <div id="app"></div>
    <script>
      "use strict";

      function loadScript(src) {
        return new Promise(function(resolve) {
          const script = document.createElement("script");

          script.setAttribute("async", true);
          script.setAttribute("src", src);
          script.addEventListener("load", resolve);

          document.head.appendChild(script);
        });
      }

      async function main() {
        await Promise.all([
          loadScript("https://unpkg.com/vue/dist/vue.js"),
          loadScript("https://unpkg.com/vue-router/dist/vue-router.js")
        ]);

        const { Vue, VueRouter } = window;

        console.log(Vue);        // ƒ Vue (options)
        console.log(VueRouter);  // ƒ VueRouter (options)
      }

      main();
    </script>
  </body>
</html>

Explainations

The function

The function I wrote is an asynchronous function. You can tell by the return value of it as being a promise. If you are not familiar with promises yet, I strongly advise you to read the Using Promise guide from Mozilla Developper's documentaton website.

That also means that it won't block the main thread when called in your script. This is ideal for us, as we are great consumers of scripts nowadays.

The main function

The main function is here because we do not have top-level await, yet. The async and await keywords are syntactic sugar to use promise in an imperative style. Again, if you are not familiar with those keywords, you can read a little about it here. I could also have written it that way:

Promise.all([loadScript("..."), loadScript("...")]).then(function() {
  //...
});

The parallel loading

You may be wondering, why I didn't wrote it with a simple for loop? Here is the code I would have wrote if I wanted to use a for loop:

const urls = [
  "https://unpkg.com/vue/dist/vue.js",
  "https://unpkg.com/vue-router/dist/vue-router.js"
];

for (const url of urls) {
  await loadScript(url);
}

But in this case, this has nothing to do with the original code I wrote. This loop will take longer because it has to wait for the first script to load before begining to load the second. Which is not very efficient. The Promise.all will just load them at the same time in parallel. Which is faster of course.

Conclusion

This is a neat little trick if you have to use a lot of script in your page because this can speed up the loading of the page. You'll still be prone to network lag and issues that I didn't cover here. I let that as an exercise for the reader. There is in particular an issue with the Promise.all call when loading buggy scripts.

What do you think? Will you use this trick in the future for your websites? Let me know in the comment section below!

Discussion (0)

pic
Editor guide