Asynchronous vs Synchronous Programming

hardy613

Scott Hardy

Posted on February 1, 2019

Asynchronous vs Synchronous Programming

Time is an illusion. Lunchtime doubly so.

  • Douglas Adams, The Hitchhiker's Guide to the Galaxy

Introduction

In programming, synchronous operations block instructions until the task is completed, while asynchronous operations can execute without blocking other operations. Asynchronous operations are generally completed by firing an event or by calling a provided callback function.

Breaking Down JavaScript

Javascript has a:

  • Callstack
  • WebAPI
  • Event Loop
  • Callback Queue

The Callstack is the immediate work your program will do.

let i = 0 // declare a mutable variable
i += 1 // add one to the variable
console.log(i) // log the variable
Enter fullscreen mode Exit fullscreen mode

In the above example, declaring a variable, adding one to the variable, and logging the variable are all three separate instructions that get added to the Callstack. WebAPI's are methods available from environments where JavaScript is run. In browsers, the window and its methods are apart of the WebAPI. When the WebAPI completes, it puts the callback on the Callback Queue.

The Event Loop waits for the Callstack to complete the loaded work. Once the Event Loop notices the Callstack is clear it will add work to the Callstack from the Callback Queue. Consider window.setTimeout with a timer of 0 and a callback function that uses a variable before it is declared.

window.setTimeout(() => console.log(i), 0)
let i = 0 
i += 1
Enter fullscreen mode Exit fullscreen mode

Instead of an error, we get the correct answer 1, this is because of the function that uses console.log is a parameter to the first WebAPI instruction window.setTimeout. The callback function is moved to the Callback Queue when the timer completes. Once the Callstack clears declaring and adding one to the variable, our function is called and it is safe to use the variable.

Starting with callbacks

A callback executes once it is added to the Callstack. In the previous example, this relied on a timer to complete, however other APIs will have other conditions. A NodeJs example:

const fs = require('fs')
const content = 'Logging to a file'
fs.writeFile('test.txt', content, err => {
    if (err) {
        throw err
    }
    console.log('logs completed')
})
console.log('end script')
Enter fullscreen mode Exit fullscreen mode

The callback is called once the writeFile API has completed:

  • opening or creating the file
  • writing to the file
  • closing the file at the location specified

fs.writeFile is asynchronous so console.log('end script') is called before the work writeFile completes.

What changes are needed to do this action synchronously?

const fs = require('fs')
const content = 'Logging to a file'
try {
    fs.writeFileSync('test.txt', content)
    console.log('logs completed')
} catch (err) {
    throw err
}
Enter fullscreen mode Exit fullscreen mode

A try {} catch() {} and the use of the synchronous write file function writeFileSync. If err is thrown the console.log is not called.

Synchronous Operations

Synchronous Operations that run block the next operation until it completes. Blocking operations may not always seem like an issue because computers are fast. For example: creating an array and logging the values in an array.

Array
    .from({ length: 5 }, (v, i) => i + 1)
    .forEach(value => console.log(value))
Enter fullscreen mode Exit fullscreen mode

However if the length was 5000 it would take longer before the array was logged. The difference in timing is a result of the thread being locked for a longer time.
Making synchronous calls to resources can lead to long response times locking up the UI until the resource responds. As an example:

const request = new XMLHttpRequest()
request.open('GET', 'https://httpstat.us', false)
request.send(null)

if (request.status === 200) {
  console.log(request.responseText)
}
Enter fullscreen mode Exit fullscreen mode

Making requests to your own services like a database can have the same effect. A common webpage will have many requests to make under unique circumstances, and as a developer, you'll want those requests to start as soon as possible but still allow the rest of the page to load what it can to enable the requests.
This is when asynchronous operations become powerful.

Asynchronous Operations

Asynchronous Operations happen independently from the main program flow. A common use for asynchronous code is querying a database and using the result. Passing in a callback is a way to interact with the response or error.

const database = require('thecoolestnewestdbframework')
database('table')
    .select('*')
    .asCallback((err, res) => {
        if (err) {
            throw err
        }
        // do something with the result
    })
Enter fullscreen mode Exit fullscreen mode

While the database loads and responds to the request, the rest of the page or other resources cannot load.

Promises and Asynchronous Operations

Promises are another way to interact with asynchronous code. In the above example if the const database returned a Promise then we could write:

const database = require('thecoolestnewestdbframework')
database('table')
    .select('*')
    .then(res => {
        // do something with the result
    })
    .catch(err => throw err)
Enter fullscreen mode Exit fullscreen mode

A Promise represents the work that is happening asynchronously. When the Promise resolves the result can be caught as an error, or used in a then method. then returns a Promise, this means then is chainable returning another Promise to the next then.

const database = require('thecoolestnewestdbframework')

database('table')
    .select('*')
    .then(res => {
        // do something with result
        return somethingDifferent
    })
    .then(res => {
        return database('other_table')
            .select('*')
            .where('id', res)
    })
    .then(res => {
        // do something else
    })
    .catch(err => throw err)
Enter fullscreen mode Exit fullscreen mode
💖 💪 🙅 🚩
hardy613
Scott Hardy

Posted on February 1, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related