1. What is async
?
async
is a keyword used to define asynchronous functions. When a function is marked async
, it implicitly returns a promise.
2. What is await
?
await
is a keyword used inside an async
function to pause execution until a promise is resolved. It can only be used inside an async
function and effectively makes asynchronous code behave like synchronous code.
3. How did we handle promises before async/await
?
Before async/await
, we used Promise chains with .then()
and .catch()
methods to handle asynchronous code. It required manually chaining operations, which sometimes led to deeply nested or hard-to-read code.
somePromise
.then((result) => {
console.log(result);
return anotherPromise;
})
.then((result) => {
console.log(result);
})
.catch((error) => {
console.error(error);
});
4. Why did we need async/await
?
We needed async/await
to solve problems of readability and complexity in promise chaining. It allows asynchronous code to look more like synchronous code, making it easier to follow.
5. How async/await
works behind the scenes
- An
async
function always returns a promise. - The
await
expression pauses the execution of theasync
function until the promise is fulfilled (resolved) or rejected. - Once resolved, the function resumes and continues with the next line of code.
- If the promise is rejected, it throws an error that can be caught using
try/catch
.
Behind the scenes, async/await is syntactic sugar over promises, but they don’t eliminate promises. Instead, they offer a clearer way to write asynchronous code.
6. Example of using async/await
async function fetchData() {
try {
const data = await someAPI();
console.log(data);
} catch (error) {
console.error("Error fetching data", error);
}
}
Here, the fetchData
function waits for someAPI()
to return its promise, and if the promise is rejected, the error is caught in the catch
block.
7. Error Handling in async/await
Error handling in async/await
is done using try/catch
blocks. This makes it easier to handle errors compared to .catch()
used with promises.
async function handleError() {
try {
const result = await somePromise;
console.log(result);
} catch (error) {
console.error("Error:", error);
}
}
If somePromise
is rejected, the catch
block will handle the error, making the code more manageable.
8. async/await
vs. .then()/.catch()
- Readability:
async/await
is more readable, resembling synchronous code, while.then()
requires chaining and nesting, which can become hard to follow. - Error Handling:
async/await
usestry/catch
for error handling, making it more intuitive. In contrast,.then()
uses.catch()
at the end of the chain for error handling. - Complexity:
async/await
reduces complexity by eliminating deeply nested promise chains.
9. What is a Response Object
, fetch()
, and Readable Stream
?
Response
Object: Represents the response to a fetch request, containing the HTTP response data. It has methods like.json()
,.text()
,.blob()
, and others to read the response body.fetch()
: A modern API to make HTTP requests. It returns a promise that resolves to aResponse
object.
fetch("https://api.example.com/data")
.then((response) => response.json()) // Parsing response to JSON
.then((data) => console.log(data));
- Readable Stream: Represents a stream of data, especially useful for handling large data like files. It allows reading data in chunks rather than all at once, making it memory efficient.
10. Syntactical Sugar: async/await
vs. .then/.catch
async/await
is considered syntactical sugar over promises because it simplifies how we write promise-based asynchronous code. Internally, the browser still handles promises, but the async/await
syntax makes it more intuitive and cleaner.
11. What is a “thenable”?
A thenable is any object with a .then()
method. This means it behaves like a promise and can be used in promise chains. Promises themselves are thenables, but any object implementing the .then()
method can also be considered a thenable.
const thenable = {
then: function (resolve, reject) {
resolve("This is a thenable");
},
};
Promise.resolve(thenable).then((result) => console.log(result));
// Output: "This is a thenable"
Example Explanations of Your Code:
1. Await with One Promise:
async function handleProm() {
const val = await p;
console.log("hfsf");
console.log(val);
}
- The program is paused until
p
is resolved, then the execution resumes. It prints “hfsf” afterp
is resolved and logsval
.
2. Two Await Statements:
async function handleProm() {
console.log("awaiting 2 times");
const val = await p;
console.log("hfsf");
console.log(val);
const val2 = await p;
console.log("hfsf");
console.log(val2);
}
- Here, “awaiting 2 times” is printed immediately, but the execution pauses until
p
is resolved. It waits forp
twice, soval
andval2
are printed sequentially after awaiting each promise.
3. Different Promise Times (10s and 5s):
async function handleProm() {
console.log("awaiting 2 times");
const val = await p1; // Takes 10 seconds
console.log("hfsf");
console.log(val);
const val2 = await p2; // Takes 5 seconds
console.log("hfsf2");
console.log(val2);
}
p1
takes 10 seconds to resolve, so “hfsf” andval
are logged after 10 seconds.p2
takes 5 seconds, so “hfsf2” andval2
are logged after another 5 seconds.