Problem understanding callback hell in JavaScript

function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2(callback) {
setTimeout(function() {
console.log("Task 2 complete");
callback(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3(callback) {
setTimeout(function() {
console.log("Task 3 complete");
callback(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(function() {
task2(function() {
task3(function() {
task4(); // no more callbacks needed
});
});
});
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2(callback) {
setTimeout(function() {
console.log("Task 2 complete");
callback(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3(callback) {
setTimeout(function() {
console.log("Task 3 complete");
callback(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(function() {
task2(function() {
task3(function() {
task4(); // no more callbacks needed
});
});
});
Hello guys, I'm not being able to understand this syntax:
// Execute the tasks in sequence
task1(function() {
task2(function() {
task3(function() {
task4(); // no more callbacks needed
});
});
});
// Execute the tasks in sequence
task1(function() {
task2(function() {
task3(function() {
task4(); // no more callbacks needed
});
});
});
The thing is task1 takes only 1 callbacks, can't we just do something like that: task1(task2) ? We are we nesting the callbacks I don't understand
19 Replies
Jochem
Jochem3w ago
task1 receives only one callback, task2. But task2 also requires a callback, so task2 receives task3. Same for 3, it receives 4 it's a bit confusing, and the anonymous functions muddy it a little further but they're necessary to pass in the arguments for tasks 2 and 3
glutonium
glutonium3w ago
if u just do task1(task2) then u canno pass task3 to task2
Faker
Faker3w ago
but the thing is, can't we do that: task1(task2); here we pass function reference task2, now inside task1(): function task1(callback) { setTimeout(function() { console.log("Task 1 complete"); callback(task3); // calling task2 when task1 finishes }, 1000); // 1-second delay } can't I pass task3 in the callback() ?
glutonium
glutonium3w ago
so in order to pass task3 to task2, u instead of just doing (task2) , u pass another callback which simply calls the task2 with appropriate argument if u instead of doing callback() inside task2, if u just directly call task3() from within task2, and task4() from within task3 then u can just so task1(task2) ,cause in that case u r directly calling task3 from task2 and task4 from task3 hence u don't have to pass any arguments
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2() {
setTimeout(function() {
console.log("Task 2 complete");
task3(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3() {
setTimeout(function() {
console.log("Task 3 complete");
task4(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(task2);
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2() {
setTimeout(function() {
console.log("Task 2 complete");
task3(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3() {
setTimeout(function() {
console.log("Task 3 complete");
task4(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(task2);
i edited on phone, so make sure if it contains no bugs looks right to me
Faker
Faker3w ago
yeah I see, this is also correct right ? why we also have the syntax // Execute the tasks in sequence task1(function() { task2(function() { task3(function() { task4(); // no more callbacks needed }); }); }); What the difference between the 2
glutonium
glutonium3w ago
between which of the 2?
MarkBoots
MarkBoots3w ago
Gluthorium has altered the task function to already call the correct next task. so no callback needed --sorry to hijack
glutonium
glutonium3w ago
yep
Jochem
Jochem3w ago
the issue is that you then cannot run task1, then 3, then 2, then 4, or have a task3a and task3b you lose flexibility, and honestly, there's very little point in using callbacks if you're going to hardcode them anyway.
Faker
Faker3w ago
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2() {
setTimeout(function() {
console.log("Task 2 complete");
task3(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3() {
setTimeout(function() {
console.log("Task 3 complete");
task4(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(task2);
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2() {
setTimeout(function() {
console.log("Task 2 complete");
task3(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3() {
setTimeout(function() {
console.log("Task 3 complete");
task4(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(task2);
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2(callback) {
setTimeout(function() {
console.log("Task 2 complete");
callback(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3(callback) {
setTimeout(function() {
console.log("Task 3 complete");
callback(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(function() {
task2(function() {
task3(function() {
task4(); // no more callbacks needed
});
});
});
function task1(callback) {
setTimeout(function() {
console.log("Task 1 complete");
callback(); // calling task2 when task1 finishes
}, 1000); // 1-second delay
}

function task2(callback) {
setTimeout(function() {
console.log("Task 2 complete");
callback(); // calling task3 when task2 finishes
}, 1000); // 1-second delay
}

function task3(callback) {
setTimeout(function() {
console.log("Task 3 complete");
callback(); // calling task4 when task3 finishes
}, 1000); // 1-second delay
}

function task4() {
setTimeout(function() {
console.log("Task 4 complete");
}, 1000); // 1-second delay
}

// Execute the tasks in sequence
task1(function() {
task2(function() {
task3(function() {
task4(); // no more callbacks needed
});
});
});
Both code do the same thing except in one code snippet, we are always passing callback, so it really depends on us which method to use to produce sequential execution ?
Jochem
Jochem3w ago
they do the same thing in this case, but the second gives you more flexibility
Faker
Faker3w ago
Passing callbacks for each function create that pyramid-like identation which we call callback hell I guess, either way, neither of these 2 methods are effective?
Jochem
Jochem3w ago
lets say task4 has two variations. Maybe this is a set of operations that sends a social media post, and task4 is sending this to the actual social media site if you use the task1(task2) version, you're SOL if you want to post to twitter or bluesky. You'd have to rewrite and potentially duplicate task2 and task3 to then be able to call task4_bluesky from task3_bluesky which is called from task2_bluesky if you use the second version, you can simply call (non-working, simplified cause I don't feel like typing it out) task1(task2(task3(task4_bluesky))) that said, I don't like this pattern, personally you're right that the whole cascading nested calling bs is unpleasant to use and hard to read and reason about
Faker
Faker3w ago
yeah I see, something like that:
// To post to Twitter
task1(function() {
task2(function() {
task3(function() {
task4_twitter(); // Here you can easily swap to Bluesky or another platform
});
});
});

// To post to Bluesky
task1(function() {
task2(function() {
task3(function() {
task4_bluesky(); // You pass task4_bluesky instead of task4_twitter
});
});
});
// To post to Twitter
task1(function() {
task2(function() {
task3(function() {
task4_twitter(); // Here you can easily swap to Bluesky or another platform
});
});
});

// To post to Bluesky
task1(function() {
task2(function() {
task3(function() {
task4_bluesky(); // You pass task4_bluesky instead of task4_twitter
});
});
});
Jochem
Jochem3w ago
exactly that's the whole point of using callbacks, so you can switch out multiple predefined behaviors depending on the needs at calltime
Faker
Faker3w ago
Yeah I see, I now have a clearer view, thanks !!
Jochem
Jochem3w ago
you're usually better off using either Promises or async/await in these cases btw. It changes this to:
task1()
.then(task2)
.then(task3)
.then(task4);
task1()
.then(task2)
.then(task3)
.then(task4);
or
const task1result = await task1();
const task2result = await task2(task1result);
const task3result = await task2(task2result);
const task4result = await task2(task3result);
const task1result = await task1();
const task2result = await task2(task1result);
const task3result = await task2(task2result);
const task4result = await task2(task3result);
Faker
Faker3w ago
yep, I will soon learn these but I already have an understanding of how async and await will work with the given example, thanks ! the whole block of the await should be in another function right? an async function ? Hmm why pass the taskResults as arguments
Jochem
Jochem3w ago
yeah, you can't use toplevel await and you'd pass the results if you need them, you can skip if it doesn't need input... but at the same time, that probably means you're using global variables to pass state around which isn't the best either
Want results from more Discord servers?
Add your server