Explain the difference between synchronous and asynchronous functions in JavaScript
TL;DR
Synchronous functions are blocking while asynchronous functions are not. In synchronous functions, statements complete before the next statement is run. As a result, programs containing only synchronous code are evaluated exactly in order of the statements. The execution of the program is paused if one of the statements take a very long time.
Asynchronous functions usually accept a callback as a parameter and execution continue on to the next line immediately after the asynchronous function is invoked. The callback is only invoked when the asynchronous operation is complete and the call stack is empty. Heavy duty operations such as loading data from a web server or querying a database should be done asynchronously so that the main thread can continue executing other operations instead of blocking until that long operation to complete (in the case of browsers, the UI will freeze).
Synchronous vs asynchronous functions
In JavaScript, the concepts of synchronous and asynchronous functions are fundamental to understanding how code execution is managed, particularly in the context of handling operations like I/O tasks, API calls, and other time-consuming processes.
Synchronous functions
Synchronous functions execute in a sequential order, one after the other. Each operation must wait for the previous one to complete before moving on to the next.
- Synchronous code is blocking, meaning the program execution halts until the current operation finishes.
- It follows a strict sequence, executing instructions line by line.
- Synchronous functions are easier to understand and debug since the flow is predictable.
Synchronous function examples
-
Reading files synchronously: When reading a file from the file system using the synchronous readFileSync method from the fs module in Node.js, the program execution is blocked until the entire file is read. This can cause performance issues, especially for large files or when reading multiple files sequentially
-
Looping over large datasets: Iterating over a large array or dataset synchronously can freeze the user interface or browser tab until the operation completes, leading to an unresponsive application.
Asynchronous functions
Asynchronous functions do not block the execution of the program. They allow other operations to continue while waiting for a response or completion of a time-consuming task.
- Asynchronous code is non-blocking, allowing the program to keep running without waiting for a specific operation to finish.
- It enables concurrent execution, improving performance and responsiveness.
- Asynchronous functions are commonly used for tasks like network requests, file I/O, and timers.
Asynchronous function examples
-
Network requests: Making network requests, such as fetching data from an API or sending data to a server, is typically done asynchronously. This allows the application to remain responsive while waiting for the response, preventing the user interface from freezing
-
User input and events: Handling user input events, such as clicks, key presses, or mouse movements, is inherently asynchronous. The application needs to respond to these events without blocking the main thread, ensuring a smooth user experience.
-
Timers and Animations: Timers (
setTimeout()
,setInterval()
) and animations (e.g.,requestAnimationFrame()
) are asynchronous operations that allow the application to schedule tasks or update animations without blocking the main thread.
By using asynchronous functions and operations, JavaScript can handle time-consuming tasks without freezing the user interface or blocking the main thread.
It is important to note that async
functions do not run on a different thread. They still run on the main thread. However, it is possible to achieve parallelism in JavaScript by using Web workers
Achieving parallelism in JavaScript via web workers
Web workers allow you to spawn separate background threads that can perform CPU-intensive tasks in parallel with the main thread. These worker threads can communicate with the main thread via message passing, but they do not have direct access to the DOM or other browser APIs.
In this example, the main thread creates a new web worker and sends it a message to start a computation. The worker performs the heavy computation in parallel with the main thread and sends the result back via postMessage()
.
Event loop
The async nature of JavaScript is powered by a JavaScript engine's event loop allowing concurrent operations even though JavaScript is single-threaded. It's an important concept to understand so we highly recommend going through that topic as well.