I use promisifyAll to the following module since I want to use it with promises and I got error "TypeError: Cannot read property 'then' of undefined"
const DBWrapper = Promise.promisifyAll(require("node-dbi").DBWrapper);
var dbWrapper = new DBWrapper('pg', dbConnectionConfig);
dbWrapper.connect();
dbWrapper.insert('USERS', data, function (err, data) {
if (err) {
console.log("error to insert data: " + err);
} else {
console.log("test" + data);
}
}).then(() => {
//read data
dbWrapper.fetchAll("SELECT * FROM USERS", null, function (err, result) {
if (!err) {
console.log("Data came back from the DB.", result);
} else {
console.log("DB returned an error: %s", err);
}
dbWrapper.close(function (close_err) {
if (close_err) {
console.log("Error while disconnecting: %s", close_err);
}
});
});
})
You have two things going on here that are incorrect from what I can tell.
You're not properly implementing the promises in the above code. Error first callbacks aren't passed in when invoking Promise returning methods, instead they pass the result value to the nearest .then(). If an error occurs they will pass that to the nearest .catch(). If there is no .catch() and an error occurs, an unhandledRejection error will be thrown.
By default, promisifyAll() appends the suffix Async to any promisified methods, so you will need to modify any method calls on dbWrapper accordingly.
Assuming node-dbi can be promisifed and that your DB calls are correct the following code should work as you were initially anticipating
const Promise = require('bluebird');
const DBWrapper = require("node-dbi").DBWrapper;
const dbWrapper = Promise.promisifyAll(new DBWrapper('pg', dbConnectionConfig));
return dbWrapper.insertAsync('USERS', data)
.then((data) => {
console.log("test" + data);
//read data
return dbWrapper.fetchAllAsync("SELECT * FROM USERS", null)
})
.then((result) => {
console.log('Data came back from DB.', result);
return dbWrapper.closeAsync();
})
.catch((err) => {
console.log('An error occurred:', err);
});
Related
let { errors } = otherValdations(data);
withDB(async (db) => {
return Promise.all([
..code...
]).then(() => {
return {
errors,
isValid: isEmpty(errors),
}
})
}, res).then((result) => {
console.log(result);
})
How can I get 'result' variable to be the value of the object returned in promise.all? This is the code for withDB function:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('app');
await operations(db);
client.close();
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error});
}
};
You need to modify withDB() so that it returns the value you want:
const withDB = async (operations, res) => {
try {
const client = await MongoClient.connect('mongodb://localhost:27017', { useNewUrlParser: true });
const db = client.db('app');
let result = await operations(db);
client.close();
return result;
} catch (error) {
res.status(500).json({ message: 'Error connecting to db', error});
throw error;
}
}
In your catch() handler, you also need to do something so that your calling code can distinguish the error path where you've already sent an error response from the case where you're resolved with the value. I don't know exactly how you want that to work, but I put in a throw error so that it will reject the returned promise and the caller can see that.
I notice from your error handling that you are assuming all possible errors are causing by an error connecting to the DB. That is not the case here. If operations(db) rejects, that will also hit your catch.
Promise.all returns an array with the results. So you either have to loop over the results or access them directly by supplying an index.
This is the code for a google cloud function I am trying to deploy. I'm getting a error saying that my .then() promises or inconsistent. Does anyone know what I am doing wrong?
const admin = require('firebase-admin');
const twilio = require('./twilio');
module.exports = function(req, res) {
if (!req.body.phone) {
return res
.status(422)
.send({ error: 'You must provide a phone number' });
}
const phone = String(req.body.phone).replace(/[^\d]/g, '');
admin
.auth()
.getUser(phone)
.then(userRecord => {
const code = Math.floor((Math.random() * 8999 + 1000));
const message = {
body: 'Your code is ' + code,
to: phone,
from: '+18053167032'
};
const callback = (err) => {
if (err) {
return res.status(422).send(err);
}
admin
.database()
.ref('users/' + phone)
.update(
{ code: code, codeValid: true },
() => { res.send({ success: true }
);
};
twilio.messages.create(message, callback);
})
.catch((err) => {
res.status(422).send({ error: err });
});
}
Off the top of my head, it is hard your indentation blocks using the curly braces exactly, and in response to #hanoldaa's mention of arrow functions, it is quite important to be able to trace exactly where the userRecord => function will end. If it says your .then promises are inconsistent, then I would assume you are either calling .then on non-promise objects, or you are not handling unresolved Promises.
Javascript.info has a great suggestion on a global handling of unresolved promises, using:
window.addEventListener('unhandledrejection', function(event) {
// the event object has two special properties:
alert(event.promise); // [object Promise] - the promise that generated the error
alert(event.reason); // Error: Whoops! - the unhandled error object
});
new Promise(function() {
throw new Error("Whoops!");
}); // no catch to handle the error
Hope this helps!
At the end, you do
.catch((err) => {
res.status(422).send({ error: err });
});
but err shouldn't be wrapped in parenthesis. Use
.catch(err => {
res.status(422).send({ error: err });
});
I'm creating an API using Node.js/TypeScript running Express. Below is an excerpt from my get method. An error is being triggered in the format method, which throws an error that is caught by the promise, but not propagated to the parent promise after a throw:
this.getModel(objectName).findAll(queryParameters).then(function(databaseObjects) {
for (let databaseObject of databaseObjects) {
var jsonObject = {};
//console.log("Database object: ");
//console.log(databaseObject);
transform.baseFormat(databaseObject, jsonObject)
.then(() => transform.format(databaseObject, jsonObject))
.then(() => {
res.locals.retval.addData(jsonObject);
}).catch((e) => {
console.log("Caught error during format of existing object: ");
console.log(e);
throw e;
});
}
})
.then(() => {
if (metadata) {
this.metadata(objectName, false, transform, res.locals.retval);
delete queryParameters.limit;
delete queryParameters.offset;
console.log("RUNNING METADATA COUNT: ");
this.getModel(objectName).count(queryParameters).then(function(count) {
res.locals.retval.setMetadata("records", count);
return next();
}).catch(function(e) {
this.error(e, res);
return next();
});
} else {
console.log("NO METADATA");
return next();
}
})
.catch((e) => {
// TODO: Move status into error() function
console.log("500 Error on GET");
console.error(e);
res.locals.retval.addError(ErrorCode.InternalError, e);
res.status(ErrorCode.InternalError).send(res.locals.retval);
return next();
});
Here's the output:
(node:8277) Warning: a promise was created in a handler at /Library/WebServer/adstudio/dist/server.js:555:51 but was not returned from it, see
at Function.Promise.bind (/Library/WebServer/adstudio/node_modules/bluebird/js/release/bind.js:65:20)
Caught error during format of existing object:
Test Error
END FUNCTION HAS BEEN REACHED!
Then the request fails to finish.
I've read a lot on Promises and I haven't been able to find an issue/solution similar to mine.
http://bluebirdjs.com/docs/warning-explanations.html
http://taoofcode.net/promise-anti-patterns/
https://www.reddit.com/r/javascript/comments/4bj6sm/am_i_wrong_to_be_annoyed_with_promise_error/
https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html
Chained promises not passing on rejection
http://wiki.commonjs.org/wiki/Promises/A
https://promisesaplus.com/
Running inside that for-loop is not asynchronous, so your promise is resolving basically as soon as the loop finishes, yet before all your formatting finishes.
Use a promise control flow, like bluebird's Promise.each which is serial or just Promise.all. Then any exceptions will be caught.
this.getModel(objectName).findAll(queryParameters).then(function (databaseObjects) {
var promises = databaseObjects.map(databaseObject => {
var jsonObject = {}
// console.log("Database object: ");
// console.log(databaseObject);
return transform.baseFormat(databaseObject, jsonObject)
.then(() => transform.format(databaseObject, jsonObject))
.then(() => {
res.locals.retval.addData(jsonObject)
}).catch((e) => {
console.log('Caught error during format of existing object: ')
console.log(e)
throw e
})
})
return Promise.all(promises)
})
.catch((e) => {
// TODO: Move status into error() function
console.log('500 Error on GET')
console.error(e)
res.locals.retval.addError(ErrorCode.InternalError, e)
res.status(ErrorCode.InternalError).send(res.locals.retval)
return next()
})
I tried node bluebird promise, I am not able to use resolve & reject in then functions.
below is my code which calls promise
modules.modelClip.exGetAllClips(sUserData)
.then(function(finalResult) {
console.log("Final result " + finalResult)
})
.error(function(e) {
console.log("Error handler " + e)
})
.catch(function(e) {
console.log("Catch handler " + e)
});
and in exGetAllClips function am returning promise.
exports.exGetAllClips = function(pUserData) {
console.log("--- inside : clipModel : exGetAllClips -----------------------------------------------------");
console.log(pUserData);
return new modules.promise(function(resolve, reject) {
modules.dbConnection.getConnection(function(rErrorCon, connection) {
if (rErrorCon) {
reject(rErrorCon);
} else {
resolve(connection);
}
});
}).then(function(connection) {
console.log('Result 4 ')
var sClipQuery = "CALL spGetAllClips(?)";
var query = connection.query(sClipQuery, [pUserData.selfId
]);
query.on('error', function(err) {
// Handle error, an 'end' event will be emitted after this as well
//return err;
console.log(" error : spGetAllClips : ",err);
reject(err);
}).on('result', function(row) {
console.log("row : ", JSON.stringify(row));
resolve( row);
}).on('end', function() {
// all rows have been received
connection.release();
})
});
};
I want to throw error from .then if exists. But wont able to do this ,it throw error reject is undefined.
Please help, how to implement this or any other way to do.
I would it like this, first there are two callbacks( one is actually an eventHandler, I am not exactly comfortable using Promises to handle that), so split them into two promises:
use getConnectionAsync instead of getConnection by promisifying the whole module.
follow bluebird docs for handling one time events( mind you, I am not maintaining a flag to check if promise is already resolved), the code could be like:
modules.dbConnection = modules.promise.promisifyAll(modules.dbConnection);
...
exports.exGetAllClips = function(pUserData) {
console.log("--- inside : clipModel : exGetAllClips -----------------------------------------------------");
console.log(pUserData);
return modules.dbConnection.getConnectionAsync()
.then(function(connection) {
console.log('Result 4 ')
var sClipQuery = "CALL spGetAllClips(?)";
return new modules.promise(function(resolve, reject){
var query = connection.query(sClipQuery, [pUserData.selfId]);
query.on('error', function(err) {
// Handle error, an 'end' event will be emitted after this as well
//return err;
console.log(" error : spGetAllClips : ",err);
reject(err);
}).on('result', function(row) {
console.log("row : ", JSON.stringify(row));
resolve( row);
}).on('end', function() {
// all rows have been received
connection.release();
});
});
};
This question already has answers here:
Chained promises not passing on rejection
(4 answers)
Closed 7 years ago.
I'm using promise object in node.js. I have a object:
var Send = {
send(post_ids) {
return Post.findById(post_ids)
.then((posts) => {
return sendArticlesToWechat(setupArticles(posts)); // sendArticlesToWechat is also a promise
})
.then((result) => {
console.log("RESULT: " + result);
})
.catch((err) => {
console.error("SEND ERROR: " + err);
return err;
});
},
}
export default Send;
and call its method in another file:
Send.send(req.body)
.then((result) => {
console.log("CALL SEND: " + result);
})
.catch((err) => {
console.error(err);
});
When an error occurs, I got two output:
SEND ERROR: ERROR: // error message
CALL SEND: ERROR: // error message
This error occurred in the sendArticlesToWechat() function which be returned. Because it's a promise too so I can catch its error outside. This is what I expected.
When I call the Send.send(), I expected to get the error in catch(), but the error appears in the then() method.
According to the output, the error did returned from the previous catch(), why I can not keep it in the catch()?
The problem is in your final catch(). Because you return err, you cause the promise to become resolved instead of rejected. If you want to return a rejected promise, then either remove the catch() or re-throw err
var Send = {
send(post_ids) {
return Post.findById(post_ids)
.then((posts) => {
return sendArticlesToWechat(setupArticles(posts)); // sendArticlesToWechat is also a promise
})
.then((result) => {
console.log("RESULT: " + result);
})
.catch((err) => {
console.error("SEND ERROR: " + err);
//return err;//converts from reject to resolved
throw err;
});
},
}
export default Send;