📘 Class Notes: Sending Callbacks
After a Request is Made to Know
How It Went
1. Introduction to Callbacks
A callback is a function passed as an argument to another function.
The purpose is to execute code after an operation completes.
In asynchronous programming (like HTTP requests), callbacks help
us know whether a request succeeded or failed.
🔑 Why do we need callbacks?
JavaScript is non-blocking. Instead of waiting for a network request to
finish, it continues running other code. The callback notifies us when the
request is complete.
2. General Callback Structure
function doSomething(callback) {
// some logic
callback(); // invoke the callback function
}
Example
function greet(name, callback) {
console.log("Hello " + name);
callback();
}
greet("Ebenezer", () => {
console.log("Greeting completed!");
});
👉 Here, the callback runs after the greeting.
3. Callbacks in Network Requests
When making HTTP requests, callbacks let us process results:
✅ Success → data is returned
❌ Failure → error is returned
3.1 Using XMLHttpRequest (Classic Example)
function makeRequest(url, callback) {
const xhr = new XMLHttpRequest();
xhr.open("GET", url, true);
xhr.onload = function () {
if (xhr.status === 200) {
callback(null, xhr.responseText); // success → data
} else {
callback("Error: " + xhr.status); // failure → error
}
};
xhr.onerror = function () {
callback("Network Error");
};
xhr.send();
}
// Usage
makeRequest("https://jsonplaceholder.typicode.com/posts/1", (err, data) =>
{
if (err) {
console.log("❌ Request failed:", err);
} else {
console.log("✅ Request successful:", data);
}
});
3.2 Using setTimeout as a Simulation
function fakeRequest(success, callback) {
setTimeout(() => {
if (success) {
callback(null, "Data received successfully!");
} else {
callback("Request failed", null);
}
}, 2000);
}
fakeRequest(true, (err, result) => {
if (err) {
console.log("❌", err);
} else {
console.log("✅", result);
}
});
👉 The callback tells us how the request went.
4. Callback Pattern: Error-First
Convention: first argument = error, second = result.
If an error occurs → pass error in first argument.
If successful → null for error and result in second argument.
Example:
function request(url, callback) {
setTimeout(() => {
if (!url.startsWith("http")) {
return callback("Invalid URL", null);
}
callback(null, "Fetched data from " + url);
}, 1000);
}
request("http://example.com", (err, data) => {
if (err) {
console.error("Error:", err);
} else {
console.log("Success:", data);
}
});
5. Callback Hell
When multiple callbacks are nested → code becomes hard to read.
Example:
makeRequest("url1", (err, data1) => {
if (!err) {
makeRequest("url2", (err, data2) => {
if (!err) {
makeRequest("url3", (err, data3) => {
console.log("All data fetched!");
});
}
});
}
});
😩 This is called callback hell or "pyramid of doom".
➡️Later, Promises and async/await were introduced to solve this.
6. Key Takeaways
1. Callbacks notify us when an async request finishes.
2. Convention: error-first callbacks.
3. Useful for success/failure handling in HTTP requests.
4. But too many nested callbacks → callback hell.
5. Promises and async/await were introduced as modern solutions, but
callbacks remain fundamental to understanding async flow.
✅ Summary:
Callbacks are a mechanism to know how a request went once it
completes. They pass either an error or a result back to the caller. This
ensures asynchronous tasks (like network requests) can notify your program
when to proceed.