<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Asynchronous JavaScript: The Old Way - Asynchronous JS using Callbacks</title>
</head>
<body>
    <h1>Asynchronous JavaScript: The Old Way - Asynchronous JS using Callbacks</h1>
    <p><em>Check the developer console for code/output</em></p>
    <script>
        // We will take a close look into Asynchronous JS with Callbacks, as it is the more traditional way to 
        // deal with asynchronicity in JS.

        // In order to learn about Asynchronous JS with Callbacks, we will build a very small fake recipe reader,
        // where we will simulate AJAX calls to get some fake recipes using setTimeout() function. Therefore, we are
        // going to simulate loading some data from a remote web server, which ofcourse would be asynchronous, using
        // some timers.

        // The way this fake recipe reader works is that first we get some fake IDs of the recipes from the remote
        // web server and then based on that, we select a recipe and then get that recipe from the remote web server.
        // Now since we're simulating here, we actually won't get the IDs or get the recipe from the remote web
        // server, but we will just create them inside the function.
        function getRecipe() {
            // To simulate the AJAX call (i.e., the call to get data from the remote web server), we use the 
            // setTimeout function.
            setTimeout(() => {
                // we are creating an array of recipe IDs to simulate that we're getting the data from the remote web
                // server (but we are not :P)
                const recipeID = [543, 299, 195, 2234];
                console.log(recipeID);

                // Now, once the data comes back from the server, we now want to get the recipe for one of these IDs
                // from the server. We do that by making an AJAX request to the remote web server in here, but since
                // we are simulating, we will simply call setTimeout function in here.
                
                // setTimeout(callback, time, paramsToCallback):
                // 'callback' parameter is a callback function which can take any number of parameters which are
                // passed to the callback through the 'paramsToCallback' parameter. The 'time' is the amount of time 
                // (in ms) after which the callback is supposed to be executed.
                setTimeout(id => {  // Here, id = recipeID[3], after the timer exhausts
                    // As this is a simulation, we will make some fake data
                    const recipe = {
                        title: 'Cheese Masala Dosa',
                        publisher: 'Sriram'
                    };
                    console.log(`${id}: ${recipe.title}`);

                    // Now let's suppose that we want to get another recipe from the same publisher, in that case,
                    // we again make an AJAX request, which is simulated as a setTimeout() function call here
                    setTimeout(pub => {
                        const recipe2 = {
                            title: 'Paneer Masala Dosa',
                            publisher: pub
                        };
                        console.log(recipe2);
                    }, 1500, recipe.publisher);

                }, 1500, recipeID[3]);
                
            }, 1500);
        }

        getRecipe();

        // In the scenario above, we had 3 callbacks nested inside one another. These are like chained/nested 
        // AJAX calls to get some data from the server. But we can see how this can get out of hand easily. Because
        // if the chaining/nesting grows to 10 chains (i.e., an AJAX request inside another AJAX request inside
        // another AJAX request so on... such that there are 10 AJAX request chains nested inside each other).
        // And this is also known as "Callback Hell". 

        // We can see a triangular shape below (w/o the comments):
        // function getRecipe() {
        //     setTimeout(() => {
        //         const recipeID = [543, 299, 195, 2234];
        //         console.log(recipeID);

        //         setTimeout(id => {
        //             const recipe = { title: 'Cheese Masala Dosa', publisher: 'Sriram' };
        //             console.log(`${id}: ${recipe.title}`);

        //             setTimeout(pub => {
        //                 const recipe2 = { title: 'Paneer Masala Dosa', publisher: pub};
        //                 console.log(recipe2);
        //             }, 1500, recipe.publisher);

        //         }, 1500, recipeID[3]);
                
        //     }, 1500);
        // }

        // This triangular shape can deepen a lot, and that's what Callback Hell is. It pretty much becomes 
        // unmanageable after some time. That's why in ES6, something known as "Promises" were introduced.
        // With Promises we can avoid the Callback Hell and have a nicer and cleaner syntax when using Async JS
    </script>
</body>
</html>