DEV Community

Cover image for Synchronous vs. Asynchronous programming in Javascript.
Sebastian Anioke
Sebastian Anioke

Posted on

Synchronous vs. Asynchronous programming in Javascript.

Javascript is a single-threaded programming language that can also be non-blocking. This simply means that javascript is a programming language that can be used to carry synchronous and asynchronous tasks.

These two programming styles give javascript a lot of power when it comes to carrying out programming tasks, most especially those that take a long time to complete.

In this article, I will discuss the differences between synchronous and Asynchronous programming, the pros and cons of each of them, and their best use cases.

Differences.

  • Normal functions return a result with the return keyword while Async functions return a Promise object (This is an object that contains the state of the promise and the value of the promise).

     function sum(a,b) {
          return a+b;
     }
    
     async function add(a,b) {
          return a + b;
     }
    
     sum(3,9)
     add(3,9)
    

    "Displaying the returned values of async and normal functions

  • Values of Normal function are gotten by calling the function while value of Async function is gotten by using the await or .then().

     function sum(a,b) {
          return `Normal function : ${3 + 9}`;
     }
    
     async function add(a,b) {
          return  a + b;
     }
    
     sum(3,9)
     await add(3,9)
    

    Getting value of async functions and normal functions

    Using .then()

     add(3,9).then((value)=> console.log(value))
    

    Getting async function values with .then

  • Most functions/methods that naturally run asynchronously require a callback function as a parameter.

     new Promise((resolve)=>resolve);
     setTimeout(()=>,1000);
     element.addEventListener("click", ()=>)
    

    In synchronous programming, functions that require other functions as parameters are called Higher Order Functions.

     function multiplyBy(num) {
          return function(arg) {
              return  num * arg;
          }
     }
     const multiplyByTwo = mutltiplyBy(2);
     const multiplyByFour = multiplyBy(4);
     multiplyByTwo(4)
     multiplyByFour(4)
    
  • The javascript engine first runs all synchronous code before running asynchronous code.

     console.log("I am the first") //synchronous
     new Promise((resolve)=>resolve("I am second")).then(console.log); //asynchronous
     setTimeout(console.log("I am the third"), 2) // asynchronous
     console.log("Should I be the last")  //synchronous
     setTimeout(console.log("Can I come ?"), 0) // asynchronous
    
    

    showing the order of execution between asynchronous and synchronous code

  • In Javascript all asynchronous codes are first sent to the web API before they are added to the call stack. Asynchronous codes are added to the call stack when all synchronous code(s) have been executed by the javascript engine and have been removed from the call stack.

     function printHello() {
     console.log('Hello from baz');
     }

     function baz() {
     setTimeout(printHello, 3000);
     }

     function bar() {
     baz();
     }

     function foo() {
     bar();
     }

     foo();
Enter fullscreen mode Exit fullscreen mode

  • Synchronous programming follows a strict sequence, which means that operations are performed, in perfect order. While one operation is being performed, other operation instructions are blocked.

        console.log("Loading file-1 ...")
        console.log("Loading file-2 ...")
        console.log("Loading file-3 ...")
    

    With synchronous programming, it would be impossible to load file-2 without loading file-1 .

    Asynchronous programming is non-blocking which means it doesn't block further execution while one or more operations are in progress. This also means that multiple operations can run simultaneously without waiting for other tasks to complete.

        new Promise((resolve)=>setTimeout(resolve("Loading file-1"),2000)).then(console.log);
    
        setTimeout(console.log("Loadinf file-2"),0);
    
        btn.addEventListener("click", ()=>console.log("Loading file-3"));
    
  • Javascript functions that take a very long time before they return can make the user interface(UI) or server unresponsive until the function has returned, resulting in a bad user experience. an example would be to use the alert function to display a message.
    The user would not be able to do anything on the web page until a response is given to the alert box.

          console.log("Loading file-1 ...")
          alert("Loading file-2 ...")
          console.log("Loading file-3 ...")
    

    Asynchronous programming enhances a user's experience by reducing the time it takes for a function to return after it has been called. It does this by running complex functions in the background so that it does not interrupt the user's experience with the application.

    For example, it takes time to fetch data from an application programming interface(API) or read a file so rather than stop all other operations we could use asynchronous programming to perform these actions. A bonus here is that the user might think that the application is running very fast.

         function load(file) {
              return new Promise((resolve)=>{
                   resolve(file)
              });
         };
    
         async function getBigData(bigFile) {
              const respone = await load(bigFile);
              console.log(`${bigFile} is ready`);
         };
    
         function getsmallData(smallFile) {
              console.log(`${smallFile} is ready`);
         };
    
         getBigData("File-1");
         loadsmallData("File-2");
         loadsmallData("File-3");
         loadsmallData("File-4");
    

    "Loading large data asynchrnously"

    "File-1" is very large and loading it synchronously can slow down our application. So we load it asynchronously by using a Promise.

    Once the javascript engine notices that getBigData() is an asynchronous function, it sends it to the web API and continues running other synchronous tasks.

    Once all synchronous tasks have been completed the event loop checks the micro tasks queue/job queue and runs getBigData() on the call stack.

  • Asynchronous code is non-blocking, which means that we can send multiple requests to a server at the same time.

         const urls = [
             'https://jsonplaceholder.typicode.com/users',
             'https://jsonplaceholder.typicode.com/posts',
             'https://jsonplaceholder.typicode.com/albums'
         ];
    
         Promise.all(urls.map((url) => {
              return fetch(url).then((value) => value.json());
              })).then((values) => {
                  console.log(values[0]);
                  console.log(values[1]);
                  console.log(values[2]);
         }).catch((error) => console.log("Opps there was an error", error));
    

    async time

    Synchronous code is blocking which means that it can only send one request and wait for that request to be answered by the server.

    synctime

With Promise.all() we could work on an array of asynchronous operations at once, which is, using the fetch() to fetch data from a database.

  • Synchronous programming is advantageous to developers because it is much easier to code. This saves the time it takes for developers to learn something that could open the door to bugs (asynchronous programming).

  • Asynchronous programming should be used in carrying out tasks that do not depend on other tasks for their execution.

         <!DOCTYPE html>
         <html>
              <p>Hello</p>
              <p>Hello</p>
              <p>Hello</p>
              <p>Hello</p>
              <p>Hello</p>
              <p>Hello</p>
              <p>Hello</p>
              <script src="animate.js"></script>
              <script src="index.js"></script>
         </html>
    

    Suppose we want to animate the p tags once the page loads using a javascript animation library (animate.js). Since our code, written in index.js depends on that, written in animate.js it is placed after it.

    The code in index.js is a dependent task because it depends on animate.js to successfully carry out its operation, while the library animate.js is an independent task because it doesn't really on any other code for its execution.

    The code is read synchronously from the p tags to the last script file, index.js and everything works just as expected. But we could do something interesting here by loading animate.js asynchronously. This means that the script file, animate.js is parsed same time the p tags are parsed to increase load time.

          <script async src="animate.js"></script>
    

    By adding the async keyword, the animate.js is loaded at the same time that all the p tags are loaded. Cool right?

    By doing this we gain an increment in the load time and our users are happy â˜ē.

  • Search engines find it easier to find web pages that make use of synchronous programming. So a business that depends on search engine optimization(SEO) to publicize its reputation and product, synchronous programming would be an advantage an appreciable advantage.

Conclusion

I hope that you have gained something new from this article and you can make wise programming decisions according to what your application requires.

Refrences

Top comments (4)

Collapse
 
enyichiaagu profile image
Amazing Enyichi Agu

This is beautiful ❤ī¸
I love it. A very nice concept and so detailed. I'll be coming back to this article.

Collapse
 
anderspersson profile image
Anders Persson

Very nice guide, and clear example, thanks.

Collapse
 
devarshishimpi profile image
Devarshi Shimpi

Great article!!!

Collapse
 
chucks1093 profile image
Sebastian Anioke

Thanks for the suggestion.