JavaScript async returns 'then not defined' - javascript

Am new to async programming, have read similar threads which all seem to have the same problem of not returning anything, whereas mine does...?
However I am still getting the error message 'Cannot read property 'then' of undefined'
function getWorkItems(iterationPath, projectId) {
var queryClient = VSS_Service.getCollectionClient(TFS_Wit_QueryAPI.WorkItemTrackingHttpClient);
var query = { query: "SELECT [System.Id] FROM WorkItem WHERE [System.IterationPath] = '" + iterationPath + "'" };
var resultOfQuery;
queryClient.queryByWiql(query, projectId).then(
function (resultOfQuery) {
return new Promise((resolve, reject) => {
resolve(resultOfQuery);
console.log("Debug: " + JSON.stringify(resultOfQuery));
})
VSS.notifyLoadSucceeded();
});
}
The above prints the debug message fine, it gets the data from the server, then errors with this when I call it elsewhere
let bar;
getWorkItems(counter.path, projectId).then ( res => {
bar = res;
console.log("Debug: should be output of query " + JSON.stringify(bar));
})
Cannot read property 'then' of undefined

getWorkItems doesn't have a return statement in it, so it's implicitly returning undefined. Also, since queryClient.queryByWiql(query, projectId) is already returning a promise, you don't need to create a promise of your own and can do the following:
function getWorkItems(iterationPath, projectId)
{
var queryClient = VSS_Service.getCollectionClient(TFS_Wit_QueryAPI.WorkItemTrackingHttpClient);
var query = { query: "SELECT [System.Id] FROM WorkItem WHERE [System.IterationPath] = '" + iterationPath + "'" };
return queryClient.queryByWiql(query, projectId);
}
If you wanted to keep that log statement and notifyLoadSucceeded in there, you can, but you still don't need to create your own promise. If you're in a .then callback, you just need to return the value that you want the promise to resolve as:
function getWorkItems(iterationPath, projectId)
{
var queryClient = VSS_Service.getCollectionClient(TFS_Wit_QueryAPI.WorkItemTrackingHttpClient);
var query = { query: "SELECT [System.Id] FROM WorkItem WHERE [System.IterationPath] = '" + iterationPath + "'" };
return queryClient.queryByWiql(query, projectId)
.then(function(resultOfQuery) {
console.log("Debug: " + JSON.stringify(resultOfQuery));
VSS.notifyLoadSucceeded();
return resultOfQuery;
});
}

Related

Promise returns undefined nodejs

i am back with a same issue for my promise returning undefined please help.
Here, i am using ipfs to save data with savedata() which takes in a json string,a document name and a secret phrase.
i am not quit sure why promise is returning undefined i have checked everything
here is the new code
index.js
exports.savedata = async function savedata(jsondata,Docname,secretuuid){
const docname = Docname
let ipfss = await main();
let datavar = await ipfss.add(jsondata);
//check if input file exists or not?
const fpath = __dirname + "\\"+ "input.json"
if (fs.existsSync(fpath)) {
}
else{
const defobj = {defaultID:"defaultID"}
fs.writeFile("input.json",JSON.stringify(defobj),function(err){
// console.log('saved!')
})
}
//create an object and put an array with defaultid:defaultid to it
//take that object and keep concatenating the new arrays[new documents]
fs.readFile("input.json","utf-8",function(err,data){
if(err){
console.log(err)
}
const rembrk1 = data.replaceAll("{","")
const rembrk2 = rembrk1.replaceAll("}","")
const newstring = JSON.stringify({[docname]: datavar.path})
const URK = uuidv4() + "rkbyavds"
const CAT = CryptoJS.AES.encrypt(String(datavar.path),secretuuid);
var ENCAT = CAT.toString()
const fstring = "{" + rembrk2 + "," + docname + ":" + CAT + "}"
fs.writeFile("input.json", JSON.stringify(fstring),function(err){
if(err){
console.log(err)
}
})
return new Promise((resolve,reject) => {
// console.log('saved')
const retobj = {CAT:ENCAT,URK:URK}
resolve(retobj)
});
})
}
test.js
obj = JSON.stringify({user:"MqwMedz2edemusaaa",age:1291})
const op = savedata(obj,"doc1","verysecretuuid")
op.then(x=>{
console.log(x)
})
Well, the RegisterUser function executes the actions and retrieves the data. What it doesn't do is return any value. This means it'll return a Promise by default, but this Promise won't have any value to resolve.
Depending on which object you want to have returned, you need to return it or create and return a new Promise from which you can call the resolve-function.
You can read more about it here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function

Firebase cloud functions: "Unhandled error RangeError: Maximum call stack size exceeded"

I have a cloud function that uses firebase and after I call it from my angular app I get the mentioned above error:
Unhandled error RangeError: Maximum call stack size exceeded
at baseKeys (/workspace/node_modules/lodash/lodash.js:3483:12)
at keys (/workspace/node_modules/lodash/lodash.js:13333:60)
at /workspace/node_modules/lodash/lodash.js:4920:21
at baseForOwn (/workspace/node_modules/lodash/lodash.js:2990:24)
at Function.mapValues (/workspace/node_modules/lodash/lodash.js:13426:7)
at encode (/workspace/node_modules/firebase-functions/lib/providers/https.js:184:18)
at /workspace/node_modules/lodash/lodash.js:13427:38
at /workspace/node_modules/lodash/lodash.js:4925:15
at baseForOwn (/workspace/node_modules/lodash/lodash.js:2990:24)
at Function.mapValues (/workspace/node_modules/lodash/lodash.js:13426:7
I've searched stack to find solutions - but in most cases there was serialization problem, that I believe DOES NOT happen here.
Here is my function:
exports.createCase = functions.region('europe-west2').https.onCall((data, context) => {
console.log("creating new case");
if (!context.auth) {
throw new functions.https.HttpsError('failed-precondition', 'This function must be called ' +
'while authenticated.');
}
const caseName = data.caseName;
// Authentication / user information is automatically added to the request.
const uid = context.auth.uid;
const name = context.auth.token.name || null;
const picture = context.auth.token.picture || null;
const email = context.auth.token.email || null;
console.log("caseName=" + caseName + " uid=" + uid + " name=" + name + " picture=" +
picture + " email=" + email);
var operationResult = new Promise ((resolve, reject) => {
var accessData : any = {};
var accessId = admin.database().ref('/access/').push();
var operationId = admin.database().ref('/operationslog/' + accessId.key + '/').push();
console.log("accessId created=" + accessId + ' || ' + accessId.key + ' operations id=' +
operationId + ' || ' + operationId.key);
let now: number = Date.now();
accessData[`/access/` + accessId.key] = new Access(caseName, uid, email);
accessData[`/operationslog/` + accessId.key + `/` + operationId.key] = {
date: now,
performedByUser: uid,
performedByMail: email,
performedByImg: picture,
performedBySystem: false,
operationType: 'CREATE',
order: (REVERSE_ORDER_MAX - now),
details: {creator: uid, name: caseName}
};
console.log('commiting data');
admin.database().ref().update(accessData).then( (value: void) => {
console.log("returning ok result");
resolve({
status: "Ok",
accessId: accessId,
description: 'Case created'
});
}, err => {
console.log("Error while trying to create case: " + err);
reject("CASE NOT CREATED");
}
).catch(exception => {
console.log("Error while trying to create case: " + exception);
reject("CASE NOT CREATED");
}
);
}
);
return operationResult;
});
and the call from Angular app:
let createCaseCall = functions.httpsCallable('createCase');
createCaseCall({caseName: value.caseName}).then(result => {
// Read result of the Cloud Function.
console.log("got result: " + result);
if (result.data.status == 'Ok') {
this.showSuccessMessage('Case created.');
}
}).catch(err => {
console.log("Error while calling cloud functions: " + err);
this.showErrorMessage('Error while creating the case.');
});
Now, the important information is that, the data in firebase realtime database IS CREATED when this function is called and console log does contain "returning ok result" line...
It is still a serialization problem.
Here's what you're trying to send back to the client:
resolve({
status: "Ok",
accessId: accessId,
description: 'Case created'
});
accessId is the result of a push operation:
var accessId = admin.database().ref('/access/').push();
That means it's a DatabaseReference object, which contains circular references that can't be serialized. It's not a simple data type, like a string.
You'll want to think more carefully about what you want exactly you want to send back to the client app. Maybe you wanted to send back the name or path of the child key that was created by push()?
Also, you'll probably want to remove the whole new Promise() thing, as that's an anti-pattern here. There is no need to create a new promise when you have promises from all the other database operations available to work with.

Retrieving first_name from Facebook Messenger results in [object Promise]

I'm writing a simple query to return the first name of a user of my Facebook Messenger chat bot, see below:
async queryFB(id) {
const fb_page_access_token = dotenv.FACEBOOK_ACCESS_TOKEN
const response = await get("https://graph.facebook.com/v3.3/"+ id + "?fields=first_name&access_token=" + fb_page_access_token);
const json = await response.json();
return json.first_name
}
async fbFirstName() {
const fbUserID = session.user.id
try {
const firstName = await queryFB(fbUserID);
console.log(firstName);
} catch(e) {
console.log("Error: " + err);
}
}
I was following this post here
The problem is that it only returns [object Promise]. I thought the solve for this was to use async and await but I still have the same problem.
After a lot of fiddling with the code I managed to solve this as follows:
function fbFetch() {
const fb_page_access_token = process.env.FACEBOOK_ACCESS_TOKEN
var fbID = 716540089
fetch('https://graph.facebook.com/v3.3/' + fbID + '?fields=first_name&access_token=' + fb_page_access_token)
.then(function(response) {
return response.json();
})
.then(function(myJson) {
var fbName = JSON.stringify(myJson.first_name);
var fbNameTrim = fbName.slice(1,-1);
console.log(fbNameTrim);
turnContext.sendActivity("Hi " + fbNameTrim + "! From inside fbFetch() before return fbNameTrim");
return fbNameTrim;
})
catch(e) {
console.log("Error: " + err);
}
}
The changes I made are as follows:
I updated the const fb_page_access_token call as it my syntax was wrong in the original post
I added .then statements to ensure that each step of the function was completed before moving on to the next to resolve some [object Promise] issues I was having
I used stringify to turn the JSON object into a string
I have used the slice function to take off the first and last characters of the string that is returned for first_name as they were inverted commas (“first_name”)

Don't understand this async await call with axios

I am using node 10+, and I have this function where I do a database query and wait for the result and return it:
var test3 = (req,res,query) => {
var conn = new sql.ConnectionPool(dbconfig);
var req = new sql.Request(conn);
var result;
return conn.connect().then(async() => {
result = await req.query(query);
conn.close();
return result;
}).catch(e => {
return e;
}).finally(() => {
conn.close();
});
}
First, I would like to know why I have to return the conn.connect() block..
return conn.connect().then(async() => {...
I know it has something to do with promise chaining I think, but I dont understand why, because my async db call is already resolved from the await dbcall function... and I just return the result from inside the function
Then, I have a router where I call the api function here:
router.get("/api/compareCount", function(req,res) {
var query = `SELECT COUNT(*) as count
FROM [DublettenReferenzmenge].[dbo].[DocumentForElasticsearch] where lastChange < dateadd(day,-1,getdate())`;
var query2 = `SELECT COUNT(*) as count
FROM [DublettenReferenzmenge].[dbo].[DocumentForElasticsearch] where lastChange < dateadd(hour,-8,getdate())`;
var query3 =`SELECT COUNT(*) as count
FROM [DublettenReferenzmenge].[dbo].[DocumentForElasticsearch]`;
axios.all([searchES(req,res), test3(req,res,query), test3(req,res,query2) , test3(req,res,query3)])
.then(axios.spread(function (esCount, mssqlCount1, mssqlCount2, mssqlCount3) {
totalES = esCount.hits.total;
totalMSSQL = mssqlCount1.recordset[0].count;
totalMSSQL2 = mssqlCount2.recordset[0].count;
totalMSSQL3 = mssqlCount3.recordset[0].count;totalMSSQL, " mssqlCount2: ", totalMSSQL2, "mssqlCount3: ", totalMSSQL3);
var msg = "ES Dokumente total: " + totalES + " MSSQL Dokumente total: " + totalMSSQL + "<br>";
if ( totalES != totalMSSQL) {
msg += "Critical: " + totalES != totalMSSQL + "<br>";
} if ((totalES != totalMSSQL2)) {
msg += "Warning: " + (totalES != totalMSSQL2) + "<br>";
} if ((totalES > totalMSSQL3)) {
msg += "Achtung es gibt ungelöschte Dokumente im Elasticsearch Index!";
}
res.set('Content-Type', 'text/html');
res.send(msg);
})).catch((err) => {
res.send(err);
});
})
router.get("/api/test3", async function (req,res) {
var query = `SELECT COUNT(*) as count
FROM [DublettenReferenzmenge].[dbo].[DocumentForElasticsearch] where lastChange < dateadd(day,-1,getdate())`;
var result = await test3(req,res,query);
res.json(result);
})
The api/test3 route returns me the result as usual, but the api/compareCount does return me correct results as well...
Furthermore, I have to use the async function ... await test3(..) async-await syntax structure to resolve my result into a variable... But I do not have to use that same structure for my api/compareCount function above, the result is returned anyways in the .then(axios.spread(function(...))). Why is that? I am quite confused as I don't really know the inner workings of the Promise chaining and calls...
EDIT: before my test3() function, I had something like this:
async function testQuery(query) {
try {
let pool = await sql.connect(dbconfig);
let result1 = await pool.request()
//.input('input_parameter', sql.Int, value)
.query(query);
sql.close();
return result1;
} catch (err) {
console.log(err);
sql.close();
} finally {
sql.close();
}
};
I got also results with that function, however, I got some kind of race condition where it told me that the sql- connection already exists, and do sql.close() first if I reload the page too quickly... I dont get this with the test3() function anymore...
To start with, test3() needs to return a promise so the caller knows when it's done and whether it had an error or not. It's probably easiest to use async/await for that:
async function test3(query) => {
const conn = new sql.ConnectionPool(dbconfig);
const request = new sql.Request(conn);
await conn.connect();
try {
const result = await request.query(query);
return result;
} finally {
conn.close();
}
}
Various changes:
Only pass arguments that are going to be used
Use await to simplify async logic flow
Use try/finally to catch any error after connected so we can always close the connection and not leak a connection
Switch from var to const.
Make function async so it returns a promise that is hooked to when the internals are done or have an error
Then, if you adjust how test3() is called to only pass the query argument (since that's all that is used), your use of that function the other places you are using it should work.
Your code was doing this:
var result = await test3(req,res,query);
But, test3() had no return value so the await had nothing useful to do. await works with a promise and you weren't returning a promise that was linked to the async operations inside of test3(). That's what my changes above do.

Javascript - Google API GET: Value null outside google api call

I am making a call to Google Calendar API for a specific event and am able to get the recurrence value.
function getRecurrence(payload) {
console.log('payload = ' + payload);
var recurrence = '';
if (payload != undefined) {
var requestRecurringEvent = window.gapi.client.calendar.events.get({
'calendarId': 'primary',
'eventId': payload
});
requestRecurringEvent.execute(function(resp) {
console.log('requestRecurringEvent = ' + resp);
console.log('requestRecurringEvent.recurrence = ' + resp.recurrence);
recurrence = resp.recurrence;
console.log('recurrence (inside execute)= ' + recurrence); //NO ISSUE (YET): recurrence (inside execute) = RRULE:FREQ=WEEKLY;COUNT=10
return recurrence;
});
} else {
return 'no recurrence value';
}
}
However, when I return the recurrence value to a variable
var recurrence = getRecurrence(action.payload.calendarEventRecurringEventId);
console.log('recurrence (outside execute) = ' + recurrence); //ISSUE: recurrence (outside execute) = undefined
note: action.payload.calendarEventRecurringEventId is because I am passing in the value from payload in redux.
Why is the value defined inside the api call but undefined outside the api call??
Thanks!
UPDATE
Promises seem to have taken me in the right direction, since the console.log('recurrence (outside execute) = ' + recurrence) prints a value, but it seems to not have completely solved the problem since an empty string is still being set for the value in redux.
var recurrencePromise = new Promise(function(resolve, reject) {
var payload = action.payload.calendarEventRecurringEventId;
console.log('action.payload.calendarEventRecurringEventId = ' + payload);
var recurrence = '';
if (payload != undefined) {
console.log('getRecurrence payload != undefined');
var requestRecurringEvent = window.gapi.client.calendar.events.get({
'calendarId': 'primary',
'eventId': payload
});
requestRecurringEvent.execute(function(resp) {
console.log('requestRecurringEvent = ' + resp);
console.log('requestRecurringEvent.recurrence = ' + resp.recurrence);
recurrence = resp.recurrence;
console.log('recurrence (inside execute)= ' + recurrence);
resolve(recurrence);
});
} else {
reject(Error("It broke"));
}
});
recurrencePromise.then(function(recurrence) {
console.log('recurrence (outside execute) = ' + recurrence);
var recurrenceTemp = 'RRULE:FREQ=WEEKLY;COUNT=10';
return {
...state,
calendarEventEndDate: action.payload.calendarEventEndDate,
calendarEventEndDateTime: action.payload.calendarEventEndDateTime,
calendarEventEndTime: action.payload.calendarEventEndTime,
calendarEventID: action.payload.calendarEventID,
calendarEventTitle: action.payload.calendarEventTitle,
calendarEventRecurringEventId: defaultIfUndefined(action.payload.calendarEventRecurringEventId, ''),
calendarEventRecurrence: recurrence, //ISSUE: this is where the value should be something like `RRULE:FREQ=WEEKLY;COUNT=10` instead of `''`
}
}, function(err) {
console.log(err); // Error: "It broke"
});
Why is the right value still not set defined outside the api call?
Because the requestRecurringEvent.execute function is asynchronous, which means you can never tell when the asynchronous function completes its execution (returns) unlike a synchronous function that guaranties a return value, async doesnt. What you need to do if you want to use the recurrence value outside is, A) Use a callback function B) use Promises (which I am sure the google api call provides by default)
I recommend you read more about asynchronity in javascript, to have a grasp on how it works.

Categories

Resources