1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
function findUser(id) {
let user;
setTimeout(function () {
console.log("waited 0.1 sec.");
user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
}, 100);
return user;
}
const user = findUser(1);
console.log("user:", user);
function findUserAndCallBack(id, cb) {
setTimeout(function () {
console.log("waited 0.1 sec.");
const user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
cb(user);
}, 100);
}
findUserAndCallBack(1, function (user) {
console.log("user:", user);
});
Alright, let’s break this down so those sneaky functions and callbacks stop feeling like a slap in the face. Your frustration is valid—this is one of the trickiest things to wrap your head around when dealing with JavaScript’s asynchronous nature. Let’s make it crystal clear.
What’s the Difference Between a Regular Function and a Callback Function?
- Regular Function:
- A function that executes immediately when it is called and returns a value directly.
- Works perfectly in synchronous code but falls apart in asynchronous situations.
- Callback Function:
- A function passed as an argument to another function.
- It’s executed later, typically after some asynchronous operation (like
setTimeout, database query, or an API call) is complete.
Code Walkthrough
Example 1: Regular Function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function findUser(id) {
let user;
setTimeout(function () {
console.log("waited 0.1 sec.");
user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
}, 100);
return user;
}
const user = findUser(1);
console.log("user:", user);
What Happens Here?
-
findUser(1)is called:- A
setTimeoutis initiated, scheduling a delay of 0.1 seconds (100ms). - The inner function inside
setTimeoutlogs"waited 0.1 sec."and assigns theuserobject after 100ms.
- A
-
return userhappens immediately aftersetTimeoutis scheduled:- At this point,
userisundefinedbecausesetTimeouthasn’t executed yet. - JavaScript does not “pause” and wait for the
setTimeoutto finish.
- At this point,
- Output:
-
"user: undefined"is logged because theuserobject wasn’t ready when the function returned.
-
Why Does It Fail?
- The function tries to return a value (
user) before the asynchronous code (setTimeout) finishes running. - In JavaScript, asynchronous code (like
setTimeout) doesn’t block the execution of subsequent code.
Example 2: Using a Callback Function
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function findUserAndCallBack(id, cb) {
setTimeout(function () {
console.log("waited 0.1 sec.");
const user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
cb(user); // Call the callback with the user object
}, 100);
}
findUserAndCallBack(1, function (user) {
console.log("user:", user);
});
What Happens Here?
-
findUserAndCallBack(1, callbackFunction)is called:- A
setTimeoutis initiated, scheduling a delay of 0.1 seconds (100ms). - After 100ms, the inner function executes, creating the
userobject.
- A
- Callback Function (
cb(user)):- The
userobject is passed to the callback function (function(user) { console.log("user:", user); }). - This callback is invoked after the
setTimeoutfinishes, ensuring theuserobject is ready.
- The
- Output:
-
"waited 0.1 sec."(from the innersetTimeoutfunction). -
"user: { id: 1, name: 'User1', email: '1@test.com' }"(from the callback).
-
Why Does It Work?
- Instead of trying to return the value directly, the
findUserAndCallBackfunction uses a callback to deliver the result when it’s ready. - The callback waits for the asynchronous operation to complete, ensuring the data is available before it is used.
Key Difference
| Aspect | Regular Function | Callback Function |
|---|---|---|
| Return Timing | Returns immediately, even if the result isn’t ready. | Executes later, only when the result is ready. |
| Asynchronous Handling | Fails to handle async operations properly. | Works with async operations by waiting for completion. |
| Use Case | Use when all data is available synchronously. | Use when dealing with async tasks like setTimeout or API calls. |
Simplified Analogy
Imagine calling a pizza delivery service:
- Regular Function: You call and expect the pizza immediately. If the pizza isn’t ready (which it isn’t), you hang up and leave hungry.
- Callback Function: You call and ask them to let you know when the pizza is ready. They call you back after it’s done, and you’re happy with your hot, fresh pizza.
Real Practice Tip
Callbacks are common, but managing them for complex workflows can lead to callback hell. To make your life easier, look into Promises or async/await, which streamline handling asynchronous operations.
Want to level up with Promises or async/await? Just let me know—I’ve got you covered! 😉
2
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// in this code,
function findUserAndCallBack(id, cb) {
setTimeout(function () {
console.log("waited 0.1 sec.");
const user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
cb(user); // 1
}, 100); // 2
}
findUserAndCallBack(1, function (user) {
console.log("user:", user);
});
// does //2 certainly start after //1?
No, //2** does not wait for **//1** to finish.** The execution of the code inside the setTimeout block is asynchronous, meaning //2 (the timer delay) begins immediately when setTimeout is called, but the actual callback function (inside setTimeout) will only execute after 100 milliseconds, independently of the flow outside.
Let’s break it down step by step:
How **setTimeout** Works in JavaScript
-
setTimeout** schedules a task to be run later**:- The code inside the
setTimeoutblock is added to the JavaScript event queue. - It won’t execute until the current execution context (all synchronous code) is finished and at least 100ms have passed.
- The code inside the
- The callback (
cb(user)):- It is executed after 100ms, assuming the JavaScript thread is free. It doesn’t block the rest of the code outside the
setTimeout.
- It is executed after 100ms, assuming the JavaScript thread is free. It doesn’t block the rest of the code outside the
Execution Order in Your Code
Code:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
function findUserAndCallBack(id, cb) {
setTimeout(function () { // 2
console.log("waited 0.1 sec.");
const user = {
id: id,
name: "User" + id,
email: id + "@test.com",
};
cb(user); // 1
}, 100);
}
findUserAndCallBack(1, function (user) {
console.log("user:", user);
});
Step-by-Step Execution:
- Call **
findUserAndCallBack**:- The function is called with
id = 1and a callback function.
- The function is called with
-
setTimeout** is scheduled** (//2):- A timer for 100 milliseconds is started.
- The callback function inside the
setTimeoutblock is queued to run after 100ms. - No blocking occurs, so the program can continue executing.
- After 100ms (timer expires):
- The JavaScript engine executes the callback function inside
setTimeout. -
"waited 0.1 sec."is logged. - The
userobject is created and passed tocb(user)(//1). - The provided callback function (
function (user) { console.log("user:", user); }) runs and logs the user.
- The JavaScript engine executes the callback function inside
Key Points
//2** does not wait for **//1:The timer (100ms) starts immediately when
setTimeoutis called. However, the execution of the callback function (and//1) happens after the timer expires.Event Loop Behavior:
The
setTimeoutcallback runs only after:- The timer expires.
- The current call stack is clear (i.e., all synchronous code has finished).
Output
Given your code, the order of execution is:
- Timer starts (
setTimeoutschedules the task for 100ms). - After 100ms,
"waited 0.1 sec."is logged. -
cb(user)runs, and"user: { id: 1, name: 'User1', email: '1@test.com' }"is logged.
Timeline Visualization
```plain text Time: 0ms –> setTimeout schedules callback (timer starts ticking) Time: 100ms –> setTimeout callback executes –> “waited 0.1 sec.” logs –> cb(user) executes, logging the user object
```
So, to reiterate:
//2** does not depend on **//1. The timer starts immediately, and **//1** executes only after the timer expires. Let me know if you’d like a deeper dive into the event loop mechanics! 😊