Someone Special
Someone Special

Reputation: 13588

Multiple Promises - Where to resolve?

I Am New To PROMISE.

I'm using nodejs promisify so I have the followings declared as promise for Redis

const { promisify } = require('util');
const getAsync = promisify(client.get).bind(client);
const hmsetAsync = promisify(client.hmset).bind(client);
const hsetAsync = promisify(client.hset).bind(client);
const incrAsync = promisify(client.incr).bind(client);
const smembersAsync = promisify(client.smembers).bind(client);
const keysAsync = promisify(client.keys).bind(client);
const sismemberAsync = promisify(client.sismember).bind(client);

I have the following function and I do not know where is the right place to put the resolve(message)

function sendMessage(senderId = '', roomId = '', text = '', type='text') {

        var message = {}
        return new Promise( function (resolve, reject) {

    if (senderId == '') {
        reject('Invalid Characters in Sender Id or Sender Id is empty.');
    }


    if (roomId == '') {
        reject('Invalid Characters in Room Id or Room Id is empty.');
    }

    if (text == '') {
        console.log('Text:' ,text);
        reject('Invalid Characters in Text or Text is empty.');
    }
            //Check if Room Exist

            keysAsync('room-'+roomId).then((value) => {

                value == '' && reject('Room '+roomId+ ' does not exist.');
                sismemberAsync('roomuser-'+roomId, senderId).then((ismember)=> {
                    ismember == 0 && reject('User ' + senderId + ' is not a member of room ' + roomId);

                    const datetime = new Date();
                    incrAsync('messageId')
                    .then((id) => {
                        //Create the message Hash
                        hmsetAsync('messsage:'+id, 'id', id, 'roomId', roomId, 'senderId', senderId, "created", datetime, "text", text);
                        //add message to Set
                        saddAsync('roommessages-'+roomId, id);

                        message = { id: id, roomId: roomId, senderId: senderId, created: datetime, text: text }
                        resolve(message) //If i place here i don't get the resolve.

                    }).catch(err => reject(err))

                }).catch(err => reject(err))

            }).catch(err => reject(err))
        })
    }

And then I tried to call the function like this

tools.sendMessage(3, 4, 'Does this work?','text').then((result)=> {
  console.log('Send Message Result => ',result);
}).catch(err => { 
  console.log(err)
});

If I were to place the resolve(message) at where it is now, the above promise doesn't resolve, and "send Message result" doesn't show at all.

If i place it further out of the chain promise, the var message returns a empty object {}

My question: Where should I place the resolve in this kind of functions where I require multiple promise calls since I need to wait for multiple redis checks?

I have many functions that requires all my redis calls to be made before I can carry on to next action.

Upvotes: 0

Views: 241

Answers (1)

Redu
Redu

Reputation: 26161

I might consider refactoring your code as follows. If you need to catch errors at interim .then() stages then use onrejected callbacks.

function sendMessage(senderId = '', roomId = '', text = '', type='text') {
  return keysAsync('room-'+roomId)
         .then(value => value === '' ? Promise.reject('Room '+roomId+ ' does not exist.')
                                     : sismemberAsync('roomuser-'+roomId, senderId))
         .then(ismember => ismember === 0 ? Promise.reject('User ' + senderId + ' is not a member of room ' + roomId)
                                          : incrAsync('messageId'))
         .then(id => { var datetime =new Date();
                       hmsetAsync('messsage:'+id, 'id', id, 'roomId', roomId, 'senderId', senderId, "created", datetime, "text", text);
                       saddAsync('roommessages-'+roomId, id);
                       return { id: id, roomId: roomId, senderId: senderId, created: datetime, text: text };
                     })
         .then(message => doSomethingWith(message))
         .catch(errorHandler);
}

In the above code i moved the new Date() to one stage below where it is actually used however if for some reason you need datetime at the original .then() stage as shown in your question then you may as well do as follows;

function sendMessage(senderId = '', roomId = '', text = '', type='text') {
  return keysAsync('room-'+roomId)
         .then(value => value === '' ? Promise.reject('Room '+roomId+ ' does not exist.')
                                     : sismemberAsync('roomuser-'+roomId, senderId))
         .then(ismember => ismember === 0 ? Promise.reject('User ' + senderId + ' is not a member of room ' + roomId)
                                          : Promise.all([incrAsync('messageId'), new Date()]))
         .then(([id, datetime]) => { hmsetAsync('messsage:'+id, 'id', id, 'roomId', roomId, 'senderId', senderId, "created", datetime, "text", text);
                                     saddAsync('roommessages-'+roomId, id);
                                     return { id: id, roomId: roomId, senderId: senderId, created: datetime, text: text };
                                   })
         .then(message => doSomethingWith(message))
         .catch(errorHandler);
}

Upvotes: 1

Related Questions