daleyjem daleyjem - 3 months ago 11
Node.js Question

Nodejs: Promise object not resolving

I have the following code. Look at the 2 lines with comments, where nothing is being output. I can't understand why the

resolve()
in the
init()
function doesn't cause the execution of
then()
in the
this.load()
function.

module.exports = function(url, list){
var phantom = require('phantom');
var Blacklist = require('../../lib/util/http/blacklist');

var blacklist = new Blacklist( list );

this.load = function(){
console.log('phantom-page:load', url);
return new Promise(function(resolve, reject){
init()
.then(function(page){
console.page('open:', url); // This doesn't output
page.open(url)
.then(function(status){
console.log('opened:', url);
resolve( page, status );
})
;
})
;
});
};

function init(){
console.log('phantom-page:init', url);
return new Promise(function(resolve, reject){
phantom.create()
.then(function(instance){
console.log('phantom-page: page created');
return instance.createPage();
})
.then(function(page){
block( page );
resolve( page );
console.log( resolve ); // This outputs [Function]
});
;
});

}

function block(page){
console.log('phantom-page:block:rawRegExp', blacklist.rawRegExp);
page.on('onResourceRequested', true, function(requestData, request, raw) {
var url = requestData['url'];
console.log('phantom-page:block:resource', url);
var regRaw = '(/' + raw + '/gi).test("' + url + '")';
var isBlacklisted = eval(regRaw);
if (isBlacklisted) {
console.log('phantom-page:block:abort', url);
request.abort();
}
}, blacklist.rawRegExp);
}

};

Answer

You are almost certainly receiving an exception in block(), and should add a .catch():

    .then(function(page){
        block( page );
        resolve( page );
        console.log( resolve ); // This outputs [Function]
    }).catch(function(e) { console.log(e) });

Your question seems to be less about why this isn't working than why your console.log() is firing and outputting [Function] and yet your caller doesn't resolve, even though you just CALLED resolve().

This is because you have a promise chain here. console.log() is executed immediately, in the current "tick". But resolve() is NOT - that will (almost - depends on the Promise library you use) always go to the next tick. That gives enough time for exceptions to fire in the meantime.

Two things can help you in addition to a .catch() (which ALL promise chains should include):

process.on('uncaughtException', function(exception) {
    console.log('uncaughtException', 'error', { message: exception.message, stack: exception.stack });
});

process.on('unhandledRejection', function(reason) {
    console.log('unhandledRejection', 'error', reason);
});

Put these somewhere at the start of your script. Whatever is going wrong, wherever it is going wrong, if you aren't trapping it you'll have a huge mystery to unravel (like you do here). These two traps can help you track down when you've forgotten to handle an error condition and they'll save you hours of debugging and head-scratching.