JavaScript Interview Questions with Example
Question: What is async/await in JavaScript?
Answer:
async
** and await
** are modern JavaScript keywords used to simplify the handling of asynchronous code, making it more readable and easier to manage. They are built on top of Promises and provide a more synchronous-like way to write asynchronous code.
Key Concepts:
async
:
-
The
async
keyword is used to declare a function as asynchronous. This means that the function will always return a Promise , and inside this function, you can use theawait
keyword to wait for asynchronous operations to complete. -
An
async
function will implicitly return a Promise, which resolves with the value returned by the function (or rejects if an error is thrown). Syntax :
async function exampleFunction() {
// Code inside an async function
}
await
:
-
The
await
keyword can only be used inside anasync
function. It pauses the execution of the function until the Promise is resolved or rejected, making asynchronous code behave more like synchronous code. -
When you use
await
, JavaScript waits for the Promise to resolve and returns the resolved value. If the Promise is rejected, an error is thrown, and you can handle it with atry/catch
block. Syntax :
const result = await promise; // Waits for the promise to resolve
How async/await works:
-
async
functions always return a Promise. -
await
makes JavaScript wait for the Promise to resolve or reject before continuing with the next line of code.
Example of async/await:
// Simulate an asynchronous operation using setTimeout
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched successfully');
}, 2000);
});
}
// Declare an async function
async function fetchDataAsync() {
try {
console.log('Fetching data...');
const data = await fetchData(); // Wait for fetchData to resolve
console.log(data); // Data fetched successfully
} catch (error) {
console.log('Error:', error);
}
}
fetchDataAsync();
Explanation :
-
fetchDataAsync
is declared asasync
, so it automatically returns a Promise. -
Inside
fetchDataAsync
, theawait fetchData()
pauses execution of the function untilfetchData()
resolves. -
When
fetchData()
resolves, the result ('Data fetched successfully'
) is assigned to the variabledata
, and it is logged to the console.
Example with error handling:
Using try/catch
allows you to handle errors in asynchronous code in a more readable way.
function fetchData() {
return new Promise((resolve, reject) => {
setTimeout(() => {
reject('Data fetch failed');
}, 2000);
});
}
async function fetchDataAsync() {
try {
const data = await fetchData(); // Wait for fetchData to resolve
console.log(data);
} catch (error) {
console.log('Error:', error); // Error: Data fetch failed
}
}
fetchDataAsync();
In this example:
-
The
fetchData
function returns a rejected Promise after 2 seconds. -
The
catch
block handles the error when the Promise is rejected, logging the error message ('Data fetch failed'
).
Benefits of async/await:
-
Readability : Asynchronous code written with
async
andawait
looks more like synchronous code, making it easier to understand. -
Error Handling : With
try/catch
blocks, error handling becomes simpler and cleaner than using.catch()
with Promises. -
Avoids Callback Hell : By avoiding nested callbacks or chaining multiple
.then()
methods, async/await makes code easier to follow.
Example of Async/Await with multiple asynchronous operations:
// Simulate an asynchronous operation using setTimeout
function fetchUser() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve({ name: 'John', age: 30 });
}, 1000);
});
}
function fetchPosts(userName) {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve([
{ title: 'Post 1 by ' + userName },
{ title: 'Post 2 by ' + userName }
]);
}, 1500);
});
}
async function getUserAndPosts() {
try {
const user = await fetchUser(); // Wait for fetchUser to resolve
console.log('User:', user);
const posts = await fetchPosts(user.name); // Wait for fetchPosts to resolve
console.log('Posts:', posts);
} catch (error) {
console.log('Error:', error);
}
}
getUserAndPosts();
Explanation :
-
The function
getUserAndPosts
usesawait
to pause execution until the data fromfetchUser
andfetchPosts
is available. -
First,
fetchUser()
is called, and once it resolves, thefetchPosts()
function is called with the username returned fromfetchUser()
. Async/Await withPromise.all()
:You can also useasync/await
in combination withPromise.all()
to run multiple asynchronous tasks concurrently:
async function getAllData() {
try {
const [user, posts] = await Promise.all([fetchUser(), fetchPosts('John')]);
console.log('User:', user);
console.log('Posts:', posts);
} catch (error) {
console.log('Error:', error);
}
}
getAllData();
Explanation :
-
Promise.all()
takes an array of promises and waits for all of them to resolve. In this case, it runsfetchUser()
andfetchPosts()
concurrently. -
await
ensures that the function waits for all promises to resolve before proceeding.
Key Points:
-
async
: Declares a function as asynchronous, which means it will always return a Promise. -
await
: Pauses the execution of an asynchronous function until the Promise is resolved or rejected. -
Error Handling :
async/await
allows you to usetry/catch
for clean error handling. -
Synchronous-like Flow : Async/await makes asynchronous code easier to read and understand, avoiding complex promise chains and callback nesting.
-
Concurrent Execution : You can use
Promise.all()
to run multiple asynchronous operations concurrently while still usingasync/await
.
Summary:
async/await
** in JavaScript provides a cleaner, more intuitive way to work with asynchronous code by making it look synchronous. It is built on top of Promises and simplifies handling async operations, especially when working with multiple asynchronous tasks. By using async
to declare a function and await
to pause execution until the Promise is resolved, developers can write more readable and maintainable asynchronous code.
Question: What is the difference between synchronous and asynchronous code in JavaScript?
Answer:
The difference between synchronous and asynchronous code in JavaScript lies primarily in how the code execution is handled with respect to time and blocking behavior.Synchronous Code:
-
Synchronous code is executed line-by-line in the order it appears in the program. Each operation must complete before the next one starts.
-
If one operation takes time (e.g., a long-running computation or a network request), it blocks the execution of the rest of the program until it completes.
-
It is often referred to as “blocking” because the program waits for one operation to finish before moving on to the next.
Example of Synchronous Code:
console.log('Start');
console.log('Middle');
console.log('End');
-
In this example, the console logs will appear in the following order:
-
Start
-
Middle
-
End
-
-
There is no delay or waiting, and the operations are performed one after another in the order they are written.
However, consider a synchronous scenario with a long-running task like reading a file (in Node.js, for example):
const fs = require('fs');
console.log('Start');
const data = fs.readFileSync('someFile.txt'); // Blocking call
console.log('File read complete');
console.log('End');
-
The program will stop and wait for
readFileSync()
to finish before it moves to the nextconsole.log()
statement. -
This can lead to performance bottlenecks, especially for tasks that take time like network requests, reading files, or heavy computations. Asynchronous Code:
-
Asynchronous code, on the other hand, allows the program to continue executing other tasks without waiting for a time-consuming operation to finish. It does not block the execution flow and is non-blocking.
-
In JavaScript, asynchronous operations (like file reading, network requests, or timers) are typically handled using callbacks , Promises , or async/await .
-
When an asynchronous operation is invoked, it is handed off to the runtime environment (e.g., the event loop in JavaScript) to execute in the background. Once it completes, the result (or error) is passed back to the program, usually via a callback function or the resolution/rejection of a promise.
Example of Asynchronous Code:
console.log('Start');
setTimeout(() => {
console.log('Middle');
}, 2000); // Non-blocking, waits 2 seconds
console.log('End');
-
Here, the
setTimeout()
function is asynchronous. It schedules theconsole.log('Middle')
to run after 2 seconds, but it doesn’t block the rest of the program. -
The logs will appear in this order:
-
Start
-
End
-
Middle
(after 2 seconds)
-
This non-blocking behavior allows JavaScript to perform other tasks while waiting for the asynchronous operation to complete. Key Differences: | Aspect | Synchronous Code | Asynchronous Code | | --- | --- | --- | | Execution Flow | Blocks further execution until the current operation finishes. | Non-blocking; the program can continue while waiting for the operation to complete. | | Order of Execution | Executes in the order written in the code. | The execution order might not be the same due to background operations. | | Blocking | Yes, it blocks subsequent operations until the current one finishes. | No, the program continues executing other code while waiting. | | Performance | Can lead to performance issues if operations take time (e.g., reading files or making API calls). | Better for performance as the event loop manages asynchronous tasks concurrently. | | Example | console.log(‘A’); console.log(‘B’); console.log(‘C’); | console.log(‘A’); setTimeout(() => console.log(‘B’), 1000); console.log(‘C’); | Synchronous Example (Blocking Behavior):
function syncTask() {
console.log('Task 1 started');
for (let i = 0; i < 1e9; i++) {} // Simulating a time-consuming task (blocking)
console.log('Task 1 finished');
}
console.log('Start');
syncTask();
console.log('End');
- In this example,
syncTask
blocks the code execution until the loop is completed. So, the output would be:-
Start
-
Task 1 started
-
(waiting for the loop to finish)
-
Task 1 finished
-
End
Asynchronous Example (Non-blocking Behavior):
-
function asyncTask(callback) {
console.log('Task 2 started');
setTimeout(() => {
console.log('Task 2 finished');
callback();
}, 1000); // Non-blocking, finishes after 1 second
}
console.log('Start');
asyncTask(() => {
console.log('Callback function executed');
});
console.log('End');
-
In this example,
asyncTask
does not block the execution. The output will be:-
Start
-
Task 2 started
-
End
-
(after 1 second)
-
Task 2 finished
-
Callback function executed
Why Asynchronous Code is Important:
-
-
JavaScript, especially in web browsers, is single-threaded. This means it can only execute one block of code at a time.
-
Asynchronous operations allow JavaScript to handle tasks like fetching data from a server, waiting for user input, or executing timeouts without freezing the entire application.
-
Without asynchronous behavior, JavaScript would be blocked, leading to poor user experience, such as unresponsive interfaces, stalled animations, and slow page loading times. Event Loop: JavaScript uses an event loop to handle asynchronous code. While synchronous code is executed immediately, asynchronous tasks are queued in the callback queue (or task queue). The event loop keeps checking if the call stack is empty and, if it is, processes the next task in the queue. This is what allows asynchronous code to run without blocking the main thread.
Summary:
-
Synchronous code executes one operation at a time, blocking further execution until each operation is complete.
-
Asynchronous code, on the other hand, allows the program to perform other tasks while waiting for operations (like network requests or timers) to complete, making it non-blocking and more efficient for handling time-consuming tasks.
Read More
If you can’t get enough from this article, Aihirely has plenty more related information, such as JavaScript interview questions, JavaScript interview experiences, and details about various JavaScript job positions. Click here to check it out.
Tags
- JavaScript
- Interview questions
- JavaScript basics
- Closures
- Event loop
- Asynchronous programming
- Callback functions
- Promises
- Async/await
- Prototypal inheritance
- DOM
- Data types
- Error handling
- Arrow functions
- Function expressions
- Function declarations
- Spread operator
- Object cloning
- JavaScript arrays
- Event delegation
- Synchronous vs asynchronous
- Object oriented programming
- ES6
- JavaScript syntax
- Debugging JavaScript
- JavaScript functions
- JavaScript scoping
- JavaScript keywords