Ever tried asynchronous iteration with promises?

I have a specific code snippet that I am working on, which involves registering multiple socketio namespaces. Certain aspects of the functionality rely on database calls using sequelize, hence requiring the use of promises. In this scenario, I intend for the complete promise to resolve only after all constructor logic has been executed. However, my current issue is that the complete promise resolves prematurely before the completion of the emitInitialPackage() function.

export class demoClass {
    public complete: Promise<boolean>;
    server: any;

    constructor(io: any) {
        this.server = io;
        this.complete = Promise.resolve(db.Line.findAll()).then(lines => {
                // do some mapping to generate routes and cells
                this.registerEndPoints(routes, [], cells);
            }).catch(err => console.log(err))
    }



registerEndPoints(routes: Array<string>, nsps: Array<any>, cells: Array<string>) {
        for (let i = 0; i < routes.length; i++) {
            nsps.push(this.server.of('/api/testNamespace/' + routes[i]));
            let that = this;
            const nsp = nsps[i];
            nsp.on('connection', function (socket) {
                that.emitInitialPackage(nsps[i], routes[i], cells[i]);
            });
        }
    }

    emitInitialPackage(nsp: any, name: string, cell: any) {
        return db.Line.find({/* Some sequelize params*/}).then(results => {
            nsp.emit('value', results);
        }).catch(err => console.log(err));
    }
}

My question is, how can I ensure that emitInitialPackage is fully completed before allowing complete to resolve?

Answer №1

For the completion of all operations in the method registerEndPoints, it is essential for this function to return a Promise that can be linked after executing the db.Line.findAll() operation:

export class uniqueClass {
    public done: Promise<boolean>;
    server: any;

    constructor(io: any) {
        this.server = io;
        this.done = Promise.resolve(db.Line.findAll()).then(lines => {
            // returning a promise created by the registerEndPoints method
            return this.registerEndPoints(routes, [], cells);
        }).catch(err => console.log(err))
    }   

    registerEndPoints(routes: Array<string>, nsps: Array<any>, cells: Array<string>) {
        const endPointPromises = routes.map((route, index) => {
          // create a Promise for each endpoint which gets resolved 
          // only when all tasks for the endpoint are completed
          return new Promise((resolve) => {
              nsps.push(this.server.of('/api/uniqueNamespace/' + route));
              const nsp = nsps[index];
              nsp.on('connection', (socket) => {
                // resolve the promise once emitInitialPackage has completed its portion of work
                this.emitInitialPackage(nsps[index], route, cells[index]).then(resolve);
              });          
          });
        });

        return Promise.all(endPointPromises);
    }

    emitInitialPackage(nsp: any, name: string, cell: any) {
        return db.Line.find({/* Specific sequelize parameters*/}).then(results => {
            nsp.emit('value', results);
        }).catch(err => console.log(err));
    }
}

Answer №2

Let's address some important issues:

  • Make sure to return the promise from this.registerEndPoints, so that this.complete will only resolve once that promise resolves;
  • The argument [] passed for the nsps parameter is unnecessary, consider removing it completely;
  • Wrap the .on('connection', ...) function in a promise;
  • Create promises within the for loop and pass them to Promise.all for the final result. You can use map for this purpose;
  • It would be better to have one array of objects instead of three separate arrays (routes, cells, and nsps) with related data at equal indexes;
  • Since bluebird is promises/A+ compliant, converting a bluebird promise to a native JS promise should not be necessary;

Below is some untested code snippet as an example:

constructor(io: any) {
    this.server = io;
    this.complete = db.Line.findAll().then(lines => {
        // map to generate routes and cells
        return this.registerEndPoints(routes, cells);
    }).catch(err => console.log(err))
}

registerEndPoints(routes: Array<string>, cells: Array<string>) {
    function nspConnect(nsp) {
        return new Promise( resolve => nsp.on('connection', resolve) );
    }
    let that = this;
    const data = routes.map( (route, i) => ({
        nsp: that.server.of('/api/testNamespace/' + route),
        route,
        cell: cells[i]
    }) );
    const proms = data.map( ({nsp, route, cell}) =>
        nspConnect(nsp).then(that.emitInitialPackage.bind(that, nsp, route, cell)) );
    
    return Promise.all(proms); 
}

To add debugging capabilities, you can modify the nspConnect function as follows:

function nspConnect(nsp) {
    return new Promise( resolve => { 
        console.log('creating promise'); 
        return nsp.on('connection', socket => { 
            console.log('resolving'); 
            resolve();
        }); 
    });
}

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

Creating UI Bootstrap dropdowns using ng-repeat on the fly

As a newcomer to AngularJS and UI Bootstrap, I am facing an issue with adding dropdowns dynamically using ng-repeat. The main problem lies in the fact that when one dropdown is clicked, it triggers all of them simultaneously. It seems like there is some mi ...

Incapable of stacking one canvas on top of another

I'm new to javascript and looking for help with positioning a canvas element behind another. The code I have may be a bit messy, so any assistance is greatly appreciated. My goal is to have the canvas named "myCanvas" appear behind "coinAnimation". Th ...

JQuery is having trouble with playing multiple sound files or causing delays with events

I've been working on a project that involves playing sounds for each letter in a list of text. However, I'm encountering an issue where only the last sound file is played instead of looping through every element. I've attempted to delay the ...

Why isn't this code performing well when trying to alter the styling of DOM elements?

JavaScript is causing major issues and is performing poorly. Why is this code not working properly?? (this is a back to top button) function checkScrollTop(){ if (document.body.scrollTop > 300) { document.getElementById("backToTop").style.dis ...

Is there a way to prevent a link from activating when I click on one of its internal elements?

Within a div nested inside an "a" tag (specifically in Link within next.js), there is another div labeled as "like." When clicking anywhere within the main div, the intention is for it to redirect to the destination specified by the "a" tag. However, if th ...

Utilizing TypeScript Generics for Creating Arrays of Objects with Inherited Type Definitions

I'm exploring the concept of type inheritance for an array of objects, where one object's value types should inherit from another. While I'm unsure if this is achievable, it's definitely worth a try. Currently, I believe my best approac ...

Is there a way to execute two files concurrently in JavaScript using node.js?

I'm a beginner in the world of Javascript and Node.js, and I've encountered some issues while trying to test code I recently wrote. Specifically, I am attempting to test the code within a file named "compareCrowe.js" using another file named "tes ...

Error: Unable to use map function on users .. cannot perform mapping on functions

Initially, the map function in my code was working fine. However, suddenly an error started appearing when I included the users.map line. Surprisingly, if I comment out that line, the code works perfectly again. Even more strangely, if I uncomment it, ev ...

What are different ways to modify a bytearray within a file using angular js, whether it is an .xlsx or other

I received a bytearray response from my API that was converted from a .xlsx file. I now need to open or download this bytearray in the browser after converting it back to its original file extension. Can anyone provide guidance on how to achieve this? I ...

Ways to position divs without causing them to collapse or override existing divs

I am currently developing a demonstration in which users can select jQuery areas to create square blocks. When a user selects an area and adds a comment with color, the entire block is displayed at a specific position. This feature is working perfectly as ...

Every time a new message is sent or received, I am automatically brought back to the top of the screen on the

I'm currently working on integrating a chat feature into my Angular Firestore and Firebase app. Everything seems to be functioning well, except for one issue - whenever a new message is sent or received, the screen automatically scrolls up and gets st ...

The ng-model binding does not automatically update another ng-model within the same object

Check out this code snippet: http://plnkr.co/edit/aycnNVoD96UMbsC7rFmg?p=preview <div data-ng-app="" data-ng-init="names=['One']"> <input type="text" ng-model="names[0]"> <p>Using ng-repeat to loop:</p> <ul> ...

React is throwing an error: Uncaught SyntaxError stating that import declarations are only allowed at the top level of a module. This issue is coming

I encountered an issue where I received the error message: Uncaught SyntaxError: import declarations may only appear at top level of a module on index.js sometimes en index.css or bundle.js Despite this error, my App is not rendering and the div with id=& ...

What is the best way to transform a string into an array?

After receiving an object from the http response, it looks something like this: {"[3, company1]":["role_user"], "[4, company2]":["role_admin"] } The key in the object is represented as an array. Is there a method in ...

Unique Version: Some effective tips for utilizing a fork of type definition such as @types

Currently, I am utilizing Typescript 2.0 along with @types and the experience has been quite positive. Thanks to @types, we can easily leverage type definitions by simply installing the package via npm. Surprisingly, I have not delved into how it actually ...

The implementation of conditional parameter types in TypeScript

I am struggling with a function where the type of the first argument is determined by the second argument's value of true or false According to my logic, if userExists is true, data should be a string and if it's false, data should be a number. ...

retain the input data from the form by using the keyup event

Currently, I have a scenario where an input field is used to capture user input. Instead of displaying the entered value directly, I am looking to store it in a variable and subsequently use it to retrieve data from a database. Below is the code snippet I ...

When utilizing JavaScript's split method, an empty string returns an array size of one instead of zero

Is there a way to separate a string using commas to create an array in Node.js? exports.test = function(rq, rs){ var mailList = "<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="16657e7764777856627365623875797b">[email ...

The issue with element.style.backgroundColor not functioning properly within WordPress

Struggling to make the background of a button change upon hover? I've got the code, but it seems to be working everywhere except in WordPress. Check out the code that should be working here: https://jsfiddle.net/TopoX84/3oqgmjb0/ Want to see it not ...

Finding the IP address from a hostname in Node.js: A step-by-step guide

I am looking for a solution to resolve a hostname defined in the hosts file to its corresponding IP address. Take, for instance, my hosts file located at "/etc/hosts": 127.0.0.1 ggns2dss81 localhost.localdomain localhost ::1 localhost6.localdomain ...