Tips on separating/callback functions based on earlier variables

Breaking Down Callback Functions Based on Previous Variables

I am trying to figure out how to efficiently break down callback functions that depend on variables defined earlier in the code. Currently, my code resembles a "callback hell" due to my lack of knowledge on organizing and breaking down callbacks effectively.

Prerequisite

Take a look at this snippet using a long callback function:

MongoClient.connect(
    process.env.MONGODBINST,
    (err, db) => {
        assert.equal(null, err)
        console.log("Connected successfully to database.")

        app.get(
            "/",
            (req, res) => {
                res.sendFile(path.join(__dirname + "./../public/index.html"))
            }
        )

        app.get(
            "/api/AmountIssuesOpen",
            async (req, res) => {
                const issuesOpen = await db.collection("GHISSUES")
                                           .find({"state": "open"})
                                           .count()
                res.send({issuesOpen})
            }
        )
    }
)

How can I separate the individual routes (app.get()) from each other? Let's explore different scenarios.

Situation 1: Breaking Down the Full Callback (working example)

const entireCallback = (err, db) => {
    assert.equal(null, err)
    console.log("Connected successfully to database.")

    app.get(
        "/",
        (req, res) => {
            res.sendFile(path.join(__dirname + "./../public/index.html"))
        }
    )

    app.get(
        "/api/AmountIssuesOpen",
        async (req, res) => {
            const issuesOpen = await db.collection("GHISSUES")
                                        .find({"state": "open"})
                                        .count()
            res.send({issuesOpen})
        }
    )
}

MongoClient.connect(
    process.env.MONGODBINST,
    entireCallback
)

Situation 2: Attempting Further Breakdown (limitations)

However, breaking it down into smaller functions becomes challenging as the second route /api/AmountIssuesOpen relies on the variable db.

const _indexRoute = (req, res) => {
    res.sendFile(path.join(__dirname + "./../public/index.html"))
}

const _AmountIssuesOpenRoute = async (req, res) => {
    const issuesOpen = await db.collection("GHISSUES")
                                .find({"state": "open"})
                                .count()
    res.send({issuesOpen})
}

const entireCallback = (err, db) => {
    assert.equal(null, err)
    console.log("Connected successfully to database.")

    // This works because the index Route doesn't need `db`
    app.get(
        "/",
        _indexRoute
    )

    // Issue arises as `db` is undefined here
    app.get(
        "/api/AmountIssuesOpen",
        _AmountIssuesOpenRoute
    )
}

MongoClient.connect(
    process.env.MONGODBINST,
    entireCallback
)

The problem with _AmountIssuesOpenRoute is that db is not defined. Passing db as an argument also doesn't resolve the issue:

const _AmountIssuesOpenRoute = async (req, res, db) => {
    const issuesOpen = await db.collection("GHISSUES")
                                .find({"state": "open"})
                                .count()
    res.send({issuesOpen})
}

Situation 3: Isolating the app.get() Routes?

Is it feasible to separate the entire app.get() functions? How could they be contained in another file and simply passed into the MongoClient.connect() callback?

const _completeIndexRoute = () => {
    app.get(
        "/",
        (req, res) => {
            res.sendFile(path.join(__dirname + "./../public/index.html"))
        }
    )
}

const _completeAmountIssuesOpenRoute = () => {
    app.get(
        "/api/AmountIssuesOpen",
        async (req, res) => {
            const issuesOpen = await db.collection("GHISSUES")
                                        .find({"state": "open"})
                                        .count()
            res.send({issuesOpen})
        }
    )
}

const entireCallback = (err, db) => {
    assert.equal(null, err)
    console.log("Connected successfully to database.")

    _completeIndexRoute
    _competeAmountIssuesOpenRoute        
}

MongoClient.connect(
    process.env.MONGODBINST,
    entireCallback
)

Answer №1

By manually including certain promises (which could also be handled using async and await), some improvement can be seen.

function connect(){
    return new Promise((resolve, reject) => {
        MongoClient.connect(
            process.env.MONGODBINST,
            (err, db) => {
                if (err) {
                    return reject(err);
                }
                resolve(db);
            }
        );
    });
}

let gotDB = connect();
gotDB.then(db => {
    console.log("Connected successfully to database.")
    app.get(
        "/",
        (req, res) => {
            res.sendFile(path.join(__dirname + "./../public/index.html"))
        }
    )

    app.get(
        "/api/AmountIssuesOpen",
        async (req, res) => {
            const issuesOpen = await db.collection("GHISSUES")
                .find({"state": "open"})
                .count()
            res.send({issuesOpen})
        }
    )
}).catch(err => {
    console.error("Could not connect to the database", err);
});

The following code demonstrates the same functionality utilizing async/await:

async function connect(){
    return new Promise((resolve, reject) => {
        MongoClient.connect(
            process.env.MONGODBINST,
            (err, db) => {
                if (err) {
                    return reject(err);
                }
                resolve(db);
            }
        );
    });
}

try {
    let db = await connect();
    console.log("Connected successfully to database.")
    app.get(
        "/",
        (req, res) => {
            res.sendFile(path.join(__dirname + "./../public/index.html"))
        }
    )

    app.get(
        "/api/AmountIssuesOpen",
        async (req, res) => {
            const issuesOpen = await db.collection("GHISSUES")
                .find({"state": "open"})
                .count()
            res.send({issuesOpen})
        }
    )
} catch {
    console.error("Could not connect to the database", err);
};

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Docusaurus font loading specifically optimized for body text, excluding headings

I've added the following CSS code to my Docusaurus custom stylesheet: @import url("https://fonts.googleapis.com/css2?family=Montserrat:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&display=swap"); :root { --ifm-color- ...

React Native: Struggling with Button Styling

I am relatively new to React Native, although I have experience with React in my professional work. I'm finding that applying styles to components in React Native is a bit different than what I'm used to. Specifically, I am struggling to apply s ...

When a div in jQuery is clicked, it binds an effect to a textbox that is

HTML: <div class="infoBox2 blackBoxHover"> <h2>Link: </h2> <input class="fileInput" type="text" id="linkText" name="linkText" /> </div> JAVASCRIPT: $('#linkText').parent('div').click(function () ...

React JS error: Trying to use props.video as a function, but it's not

As a newcomer to React, I'm encountering some errors that I need help debugging. Error #1: Uncaught TypeError: props.videos.map is not a function at new VideoList Error #2: bundle.js:19956 Error: findComponentRoot(..., .0.0.0): Unable to find el ...

Exploring Angular 2 Beta 8: An Introduction to @Query Usage

My attempt to utilize @Query to fetch data regarding an element in my template has not been successful. I made an effort using the following approach: Referenced here. Here is a snippet of my code, import {Component, Query, QueryList, ElementRef} from &a ...

Replicate the preceding input data by simply clicking a button

Here is some HTML and jQuery code that I am working with: $(".btn-copy").click(function() { var previousContent = $(this).prev()[0]; previousContent.select(); document.execCommand('copy'); }); <script src="https://cdnjs.cloudflare.com ...

Adding elements to an array within an object utilizing Mongoose

Having trouble updating the posts array in my data object. Here is the schema I'm working with: const mongoose = require('mongoose'); const Post = require('./post'); const Review = require('./comment') const User = ...

Press the Button on the Website using an automated script

I am looking for a solution to increase engagement on my website, which has external like buttons from likebtn.com. To incentivize users to utilize the like buttons, I currently have a script in place that randomly assigns likes to various posts. Howe ...

converting a CSV string into a JSON array using AngularJS

My data is in a comma-separated format: "HotelName","Remained","Date" "Maxx","4","Jun 26 2016" "Voyage","3","Jun 24 2016" I am looking to convert this into a JSON array as shown below. How can I achieve this using my JavaScript code? [ { HotelName ...

Looking to construct dynamic checkboxes in Angular by parsing a JSON object retrieved through AJAX

I have a JSON document structured like the example below, and I am looking to generate checkboxes dynamically using Angular. let data = { "Name":[ { "tagId":4489,"name":"Name","label":"Employee Name" } ], "Service":[ { "tagId": ...

Exploring the process of retrieving outcomes from Node.js within a Knockout ObservableArray

Below is the Node.js code snippet I have: var http = require('http'); var port = process.env.port || 1337; var MovieDB = require('moviedb')('API KEY'); MovieDB.searchMovie({ query: 'Alien' }, function (err, res) { ...

When performing an Angular HTTP post, additional parameters are automatically included in the request

Within a directive, I have the following code block: scope.progressCourse = -> req_data = course_id: scope.course.id success: true $http.post( "<%= Rails.application.routes.url_helpers.progress_course_path %>", req_data ).t ...

Discovering the absent number within a cyclical array

Looking to find the missing number between two arrays in a cyclical manner using either Javascript or jQuery. It's easy to find all missing numbers, but I specifically need to identify the single missing number within the range of the second array whi ...

The image source is visible in Vue.js, but unfortunately, my picture is not showing up

Below is the code and script that I have: <template> <div class="tasks_container"> <div class="tasks_content"> <h1>Tasks</h1> <ul class="tasks_list"> ...

Bits of code and the internet

When it comes to displaying code on the web, there are a few key steps involved: Encoding HTML entities Formatting The most basic workflow would involve: Start with a code snippet like: <html> I'm a full page html snippet <html>. ...

Add a dynamic widget to a specific element in the document object model in real time

Is there a way to dynamically create a jQuery UI widget using a string? You can easily do this by following the example below: $(function() { $("selector").widget() }) However, what I am trying to accomplish is slightly different. Here is an examp ...

Determine the mean value from an array of JSON objects in an asynchronous manner

Can you help me calculate the average pressure for each device ID in this JSON data set? [ { "deviceId": 121, "Pressure": 120 }, { "deviceId": 121, "Pressure": 80 }, { "deviceId": 130, "P ...

I'm wondering if there exists a method to arrange a multi-array in javascript, say with column 1 arranged in ascending order and column 2 arranged in descending order?

Here is an example of a randomly sorted multi-array: let arr = [[3, "C"], [2, "B"], [3, "Q"], [1, "A"], [2, "P"], [1, "O"]]; The goal is to sort it in the following order: arr = [[1, "O" ...

Issues arise with the functionality of custom jQuery sliders

I'm attempting to create a bootstrap panel slider using my own jQuery code, but it's not functioning as anticipated. My Objective: I have two links for "previous" and "next", and three panels with distinct headings. When the "previous" link is ...

Color-Thief Node plugin reported an issue: "The provided image has not finished loading."

While working in Node/Express, I attempted to utilize the npm package color-thief to extract the dominant color from an image. Unfortunately, it failed with the error message stating that the "image given has not completed loading". The intriguing part is ...