netsocket
netsocket

Reputation: 137

Is it possible to resolve a promise while returning?

I'm trying to resolve a promise, however it seems that when I do this:

if (o.TotalCollectionSize - 20 <= index) {
   var selectedserver = games.gameservers[Math.floor(Math.random() * games.gameservers.length)]
   console.log(selectedserver)
   resolve(selectedserver)
   return;
  }

The promise doesn't resolve, however if the resolve is outside of this if statement, the resolve will work.

(o.TotalCollectionSize - 20 <= index) 

this statement will always be true, I need it to stop once it gets to this point, that is why i'm having it resolve here.

The console.log(selectedserver) works fine, and shows me what I need resolved. My issue is that once it gets to the point it needs to resolve at, it doesn't.

getPing(game.placeId, 0).then(function (r) {
            console.log(r)
            res.end(JSON.stringify(r))
      })

getPing is a function that returns a new promise, the (r) value be what is resolved. As mentioned before, my resolve() works outside of the if statement, and I'm not sure why it doesn't work inside. I'm new to promises, so it could be a minor issue.

Edit: This is the entire function for those who need to see,

var getPing = function (id,index) {

return new Promise(function (resolve, reject) {


    options.agent = keepAliveAgent
    index = index || 0;

    var r = https.request(options, function (res) {

        var data = []
        res.on('data', function (d) {
            data.push(d)
        }).on('end', function () {
            var buf = Buffer.concat(data)
            var encodingheader = res.headers['content-encoding']
            if (encodingheader == 'gzip') {

                zlib.gunzip(buf, function (err, buffer) {
                    var o = JSON.parse(buffer.toString())
                    // o is what is returned

                    if (o.TotalCollectionSize - 20 <= index) {
                        console.log(o.TotalCollectionSize - 20, '<=', index)
                        var selectedserver = games.gameservers[Math.floor(Math.random() * games.gameservers.length)]
                        console.log(selectedserver)
                        resolve(selectedserver)
                        return;
                    }

                    if (index < o.TotalCollectionSize) {
                        index = index + 10;
                        console.log(index, o.TotalCollectionSize)
                        o.Collection.sort(function (a, b) {
                            return a.Ping > b.Ping
                        })

                        if (typeof (o.Collection[0]) != "undefined") {
                            var playerscapacity = o.Collection[0].PlayersCapacity.charAt(0)
                            if (playerscapacity != o.Collection[0].Capacity) {
                                games.gameservers.push(o.Collection[0])
                            }
                        }
                        getPing(id, index)
                    }

                })
            }
        })
    })

    r.end()
    //reject('end of here')
})
}

Like I mentioned, all of those code works perfectly fine up until it comes time to resolve the promise.

Upvotes: 0

Views: 108

Answers (1)

JLRishe
JLRishe

Reputation: 101662

I'm going to attempt to answer this without really knowing what your function is supposed to do or how it's supposed to work (because you haven't told us), so bear with me.

One rule of thumb with promises is that new Promise should be used sparingly, and when it is used, it should be kept as simple as possible. It should contain only the non-Promise asynchronous functionality that you're trying to promisify, and the rest of your logic should be working on the promises that you obtain from that. It shouldn't be a giant container for a callback-laden mess.

In your case, you have two asynchronous operations: a buffered HTTP request and GZIP extraction, so let's create separate functions for those:

function requestBufferedData(options) {
    return new Promise(function (resolve, reject) {
        // TODO: Needs to reject() in situation where request fails or else
        //       this promise will never complete when there's an error
        var r = https.request(options, function (res) {
            var data = []
            res.on('data', function (d) {
                data.push(d);
            }).on('end', function () {
                resolve({ 
                    data: Buffer.concat(data),
                    encoding: res.headers['content-encoding'],
                });
            });
        });

        r.end();
    });
}

function extractGzip(data) {
    return new Promise(function (resolve, reject) {
        zlib.gunzip(data, function (err, buffer) {
            if (err) { reject(err); }
            else { resolve(buffer); }
        });
    });
}

Now that we have these, we can breathe a little more easily. After about 10 minutes of looking at the rest of your code, I still can't make heads or tails of it, so I'm going to have to power through it. What's clear is that you have a recursive process that retries your HTTP requests until it finds the value it wants, so we'll go with that:

function getPing(id, index) {
     options.agent = keepAliveAgent;

     return requestBufferedData(options)
         .then(function (result) {
             if (result.encoding !== 'gzip') {
                 throw new Error('Response is not gzip');
             }

             return extractGzip(result.data);
         })
         .then(JSON.parse)
         .then(function (o) {
             if (o.TotalCollectionSize - 20 <= index) {
                 console.log(o.TotalCollectionSize - 20, '<=', index)
                 var selectedserver = games.gameservers[Math.floor(Math.random() * games.gameservers.length)]
                 console.log(selectedserver)
                 return selectedServer;
             }

             if (index < o.TotalCollectionSize) {
                 var nextIndex = index + 10;
                 console.log(nextIndex, o.TotalCollectionSize)
                 o.Collection.sort(function (a, b) {
                     return a.Ping > b.Ping
                 });

                 if (typeof (o.Collection[0]) != "undefined") {
                     var playerscapacity = o.Collection[0].PlayersCapacity.charAt(0);
                     if (playerscapacity != o.Collection[0].Capacity) {
                         games.gameservers.push(o.Collection[0])
                     }
                 }

                 return getPing(id, nextIndex);
             }

             throw new Error("Didn't match either condition");
         });
}

I believe this should correctly resolve the promise when the condition is met, but I have no way of testing this, so let me know if you still have trouble with this.

Upvotes: 1

Related Questions