Adding bluebird promise to NodeJS module, then function is not defined - javascript

I'm new to promise and bluebird, in my current project, I have to deal with a lot async API calls, therefore I want to use JS promise as my main tool.
One of my imported module looks like this:
var Promise = require("bluebird");
var watson = Promise.promisifyAll(require('watson-developer-cloud'));
var conversation = watson.init();
exports.enterMessage = function (inputText) {
var result; //want to return
conversation.message({
input: {
"text": inputText
}
}, function(err, response) {
if (err) {
console.log('error:', err);
result = err;
}
else {
result = response.output.text;
}
});
console.log(result); //sync call, result === undefined
return result;
}
My question is how should I approach this question? I understand the example about using promise with IO such like fs. So I try to mimic the way by doingconversation.message(...).then(function(response){result = response.output.text}), but it says conversation.message(...).then() is not defined.

Thanks to jfriend00's link, I fixed my logic and used the correct way to handle this async call.
Here is the fixed code:
//app.js
var Promise = require("bluebird");
var conversation = Promise.promisifyAll(require('./watson-conversation'));
conversation.enterMessage(currentInput).then(function(val){
res.send(val)}
).catch(function(err){
console.log(err)
});
});
//watson-conversation.js
var conversation = watson.init();
exports.enterMessage = function (inputText) {
return new Promise(function(resolve, reject){
conversation.message({
input: {
"text": inputText
}
}, function(err, response) {
if (err) {
console.log('error:', err);
reject(err);
}
else {
resolve(response.output.text);
}
});
});
}

Related

Class/ function result use in following code

I am a beginner in javascript and am now trying to understand the subject of classes. I've defined the following class. Now I would like to use the result outside of this in a variable.
The class looks like this:
class Maad{
constructor(name, NumWeek, NumMonth){
this.name =name;
this.NumWeek = NumWeek;
this.NumMonth = NumMonth;
}
queryMaad(){
const mongodb =require('mongodb');
const client = require('mongodb').MongoClient;
const url= 'mongodb://localhost:27017/vertrieb';
client.connect(url,(error, db) =>{
if(!error){
console.log("month_log steht")
};
let col = db.collection("umsatz5");
col.aggregate([{'$match': {'AD': this.name}}, {'$match': {'Kalenderwoche':this.NumWeek}}, {'$count': 'procjetnumber'}],function(err, result){
if (err) {
console.error("Error calling", err);
}
console.log(result[0].projectnumber);
result[0].projectnumber;
})
db.close();
});
}
}
My request is:
let ma_1 = new Maad("Hans Wurst", NumWeek);
ma_1.queryMaad();
How can I save the result (the number of projects) in a variable to use it outside of the class? Thanks for your help.
In general, you would assign it basically the way that you assign anything:
const ma_1 = new Maad("Hans Wurst", NumWeek);
const myVar = ma_1.queryMaad();
However your method is a void method which doesn't return anything, so you need to edit your class if you want to get the number of projects.
Returning something from the function is harder than it sounds because MongoClient.connect is a void method which uses callbacks rather than returning a Promise of a response. Honestly I would recommend using a library like mongoose. But it is possible to make the method asynchronous ourselves by returning a new Promise which we resolve or reject based on the callbacks.
class Maad {
constructor(name, NumWeek, NumMonth) {
this.name = name;
this.NumWeek = NumWeek;
this.NumMonth = NumMonth;
}
async queryMaad() {
const url = "mongodb://localhost:27017/vertrieb";
return new Promise((resolve, reject) => {
MongoClient.connect(url, (error, db) => {
if (error) {
reject(error);
}
console.log("month_log steht");
let col = db.collection("umsatz5");
col.aggregate(
[
{ $match: { AD: this.name } },
{ $match: { Kalenderwoche: this.NumWeek } },
{ $count: "procjetnumber" }
],
function (err, result) {
if (err) {
reject(err);
}
resolve(result);
}
);
db.close();
});
});
}
}
Now queryMaad is an async method, one which returns a Promise. That Promise will resolve to the result of col.aggregate on success (you could also resolve to result[0].projectnumber). The promise will reject if there is an error in the connect or col.aggregate methods.
You now get your value like so (probably inside of a function which is itself async):
const result = await ma_1.queryMaad();
You can catch rejection errors here, or allow them to be thrown and catch them higher up.
try {
const result = await ma_1.queryMaad();
} catch (error) {
// console.error or whatever
}

Issue in promise based recursive function

I am working on AWS Lambda using nodejs environment. I have one API in which I am using recursive function for some functionality.
Actually most people say avoid recursive function but as per my functionality I need this. My functionality is as follows.
I have one table table1 in which there are two columns pid and cid which is defined as unique constraint. Which means combination of two columns should be unique.
So if I am inserting any combination in table1 and it that combination already exist then it gives me duplicate entry error which is correct as per my functionality.
So in order to handle this duplicate entry error I have used try..catch block. So in catch block I have checked if duplicate entry error occurred then I am calling one recursive function which try different combination until new entry is created in table1.
And my recursive function is promise based. but when new entry in created successfully then I am resolving the promise. But promise does not get returned from where I have called my recursive function for very first time. And because of that timeout occurs.
So please someone suggest me solution so that my promise got resolved and my functionality will continue from point where I have called my recursive function for very first time. So the timeout will not come.
I am providing my code for reference.
var mysql = require('mysql');
var con = mysql.createConnection({
"host": "somehost.com",
"user": "myusername",
"password": "mypassword",
"database": "mydatabase"
});
exports.handler = async (event, context) => {
try {
con.connect();
} catch (error) {
throw error;
return 0;
}
let tableId = '';
let count = '';
try {
var tempUsageData = {
user_id: userId,
code: code,
platform: source,
some_id: some_id,
count: count
};
dbColumns = 'user_id, code, platform, added_on, count, some_id';
let usageData = [
[userId, code, source, new Date(), count, some_id]
];
var tableInsert = await databaseInsert(con, constants.DB_CONSTANTS.DB_USAGE, dbColumns, usageData);
tableId = tableInsert.insertId;
} catch (error) {
console.log('## error insert table1 ##', error);
if (error.errno == 1062) {
try {
// calling recursive function here
let newTableData = await createTableEntry(con, tempUsageData);
tableId = newTableData.new_usage_id;
count = newTableData.new_count;
} catch (error) {
console.log('Error', error);
return 0;
}
} else {
return 0;
}
};
console.log('## EXECUTION DONE ##');
return 1;
}
var createTableEntry = (con, dataObject) => {
return new Promise(async function (resolve, reject) {
console.log('createTableEntry Called for count', dataObject.count);
try {
var newCounter = await getDataFromDatabase(con, dataObject.some_id);
dbColumns = 'user_id, code, platform, added_on, count, some_id';
let tableData = [
[userId, code, source, new Date(), Number(newCounter[0].counter + 1), some_id]
];
var tableInsert = await databaseInsert(con, 'table1', dbColumns, tableData);
let response = {
new_table_id: tableInsert.insertId,
new_count: Number(newCounter[0].counter + 1)
}
return resolve(response);
//function not returning from here once successful entry done and timeout occures
} catch (error) {
console.log('## ERROR ##', error);
if (error.errno == 1062) {
console.log('## CALL FUNCTION AGAIN ##');
dataObject.count = Number(newCounter[0].counter + 1);
await createTableEntry(con, dataObject);
} else {
return reject(error);
}
}
});
};
My final output should be message "EXECUTION DONE" should be displayed once execution done.
Please suggest me good solution for this. Thanks in advance.
Update your catch block
catch (error) {
console.log('## ERROR ##', error);
if (error.errno == 1062) {
console.log('## CALL FUNCTION AGAIN ##');
dataObject.count = Number(newCounter[0].counter + 1);
let result = await createTableEntry(con, dataObject);
return resolve(result);
} else {
return reject(error);
}
}

Javascript Promise prematurely resolving

I have a function that returns a Promise, that accesses the database and pulls a few lines out, assigning them to a Javascript variable.
The issue is that my '.then' clause is being triggered even though I know the Promise hasn't resolved:
app.post("/api/hashtag", function (req, res) {
FindPopularRumours().then(function (resolveVar) {
console.log(resolveVar);
console.log();
res.send(resolveVar);
}).catch(function () {
console.log("DB Error!");
res.send("DB Error!");
});
});
And the Promise function:
function FindPopularRumours() {
return new Promise((resolve, reject) => {
var hashtags = [];
var dbPromise;
db.collection(HASHTAGS).find().forEach(function (doc) {
hashtags.push(doc.hashtag);
console.log(hashtags);
});
resolve(hashtags);
});
}
The result output is:
[ ]
['#test1']
['#test1', '#test2']
['#test1', '#test2', '#test3']
As you can see, the first line ('[ ]') should ONLY be executed AFTER the hashtags have been output. But for some reason my code seems to think the Promise has been resolved before it actually has.
EDIT1
As per Ankit's suggestion, I have amended my function to:
function FindPopularRumours() {
return new Promise((resolve, reject) => {
var hashtags = [];
db.collection(HASHTAGS).find({}, function (err, doc) {
if (!err) {
doc.forEach(function (arg) {
hashtags.push(arg.hashtag);
console.log(hashtags);
});
resolve(hashtags);
} else {
return reject(err);
}
});
});
}
This still returns the same output response as before (e.g the 'then' clause is running before the promise itself).
My POST function is still the same as before.
The db.collection.find() function is async, so you have to resolve the promise inside the callback for that, something like
function FindPopularRumours() {
return db.collection(HASHTAGS).find().toArray().then( (items) => {
return items.map( doc => doc.hashtag);
});
}
takes advantage of the Mongo toArray() method, that returns a promise directly
Please note that db.collection(HASHTAGS).find() is an asynchronous call. So, your promise is resolved before database query returns. To solve this problem, you need to re-write your database query as follows:
function FindPopularRumours() {
return new Promise((resolve, reject) => {
var hashtags = [];
var dbPromise;
db.collection(HASHTAGS).find({}, function(err, doc){
if(!err){
doc.forEach(function (arg) {
hashtags.push(arg.hashtag);
console.log(hashtags);
});
resolve(hashtags);
}else{
return reject(err);
}
});
});
}
Hope the answer helps you!

Node js array dashboard

I'm doing the backend of my app with node js. In this case i'm trying to get the typical dashboard like facebook, instagram,....
Where for one user i'm trying to get the users that he follows. And when i get the array of users following, i find the "recetas" that they have (one user can have more than one). And finally i add all this recetas in an array but the problem is that is returning me empty.
getDashboard = function (req, res) {
var myarray = new Array();
//myarray = [];
User.findById(req.params.id, function (err, user) {
if (!user) {
res.send(404, 'User not found');
}
else {
var a = user.following;
a.forEach(function (current_value) {
Receta.find({ "user_id": current_value._id }, function (err, recetas) {
if (!err) {
recetas.forEach(function (receta) {
myarray.push(receta);
}
} else {
console.log('Error: ' + err);
}
});
})
res.send(myarray);
}
});
};
You are dealing with a common async issue. Receta.find is asynchronous, it is not a blocking operation, so res.send is called before all of your Receta.find calls have completed. You can get around this issue by using Promises, assuming they are available in your version of Node:
var a = user.following;
var promises = a.map(function(current_value) {
return new Promise(function(resolve, reject) {
Receta.find({"user_id":current_value._id}, function (err, recetas) {
if(!err) {
resolve(recetas);
} else {
reject(err);
}
});
});
});
Promise.all(promises).then(function(allData) {
res.send(allData);
}).catch(function(error) {
res.send(error);
});
If native Promises aren't available, you can use a library like Q or bluebird
res.send(myarray); is being called before a.forEach completes due to Receta.find which is I/O.
call res.send only when the loop is finished and recetas returned.

Promisifying xml2js parse function (ES6 Promises)

I'm trying to refactor some node code that is a whole mess of callbacks. I thought that would be nice give promises a try for this purpose. I'm trying to convert some xml string to json with the xml2js node module. The original code was:
"use strict";
var xml2jsParser = require('xml2js').parseString;
var string = "<container><tag3>option3</tag3></container>";
xml2jsParser(string, function(err, result)
{
console.log(result);
});
and this displays:
{ container: { tag1: [ 'option1' ], tag2: [ 'option2' ], tag3: [ 'option3' ] } }
Following the first answer on this question How do I convert an existing callback API to promises? I tried to wrap the xml2jsParser function using promises in the following way:
"use strict";
var xml2jsParser = require('xml2js').parseString;
function promisesParser(string)
{
return new Promise(function(resolve, reject)
{
xml2jsParser(string, resolve);
});
}
var string = "<container><tag3>option3</tag3></container>";
promisesParser(string).then(function(err, result){
console.log(result);
});
This displays undefined through the console instead of the json object as expected. I don't understand why this happens as I was able to successfully do the same with other functions. I know something similar can be achieved with Bluebird promisify functionality but I'd like to do this on plain Javascript without any third party libraries.
Another option is to use native util module's promisify method, available from Node 8.0:
const xml2js = require('xml2js');
const util = require('util');
xml2js.parseStringPromise = util.promisify(xml2js.parseString);
// await xml2js.parseStringPromise(.. your xml ..);
You are going to need to wrap it up like this:
return new Promise(function(resolve, reject)
{
xml2jsParser(string, function(err, result){
if(err){
reject(err);
}
else {
resolve(result);
}
});
});
Then use it like this:
promisesParser(string).then(function(result){
console.log(result);
}).catch(function(err){
//error here
});
There are 2 issues...
You have to resolve with a value if it passes...and reject with an error when it fails
You need to add a catch block to you promise handling chain to catch errors.
var xml2jsParser = require('xml2js').parseString;
function promisesParser(string)
{
return new Promise(function(resolve, reject)
{
xml2jsParser(string, function(err, result) {
if (err) {
return reject(err);
} else {
return resolve(result);
}
});
});
}
var string = "<container><tag3>option3</tag3></container>";
promisesParser(string)
.then(console.log)
.catch(console.log);
I might be too late to this answer, but I thought to share what I have been using
One can use parseStringPromise method of xml2js with await keyword inside an async function.
import { parseStringPromise } from 'xml2js'
export const main = async () => {
const leadsData = await parseStringPromise(docBody)
console.log(leadsData)
}

Categories

Resources