Returning object from promise function [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 10 months ago.
I'm trying to return the list created with the value received from API to where it was called. I'm using Promise to make sure the function returns the value after it gets the value from calling API. To better explain with the code, I have a function callAPI that calls getNamedEntity. Ultimately, I want callAPI to receive the result of request.post() in getNamedEntity. However, I get Promise object and undefined when I test with console.log("outside " + result) and console.log("inside doRequest " + result) inside each function respectively.
function callAPI(text) {
const result = getNamedEntity(text);
console.log("outside " + result);
}
async function getNamedEntity(text) {
var requestJson = {
...
};
var options = {
...
};
function doRequest(options) {
return new Promise(function (resolve, reject) {
request.post(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
const result = resolve(body);
console.log("inside doRequest " + result);
} else {
reject(error);
}
});
});
}
doRequest(options)
.then((body) => {
var entityList = [];
const obj = JSON.parse(body);
const words = obj.return_object.sentence[0].NE;
for (var word of words) {
entityList.push(word.text);
}
return entityList;
})
.catch((error) => {
console.log(error);
});
}
outside [object Promise]
inside doRequest undefined

console.log("outside " + result) returns a promise object cause you forgot to await the getNamedEntity(text); or, alternately, put the console.log inside a .then, like getNamedEntity(text).then(result => console.log(result));
console.log("inside doRequest " + result); returns undefined because the resolve function returns void, ie, it returns nothing. Change to console.log("inside doRequest " + body); or move the console.log into the .then((body) portion.

Related

Issues with Async/Await during SOAP API call Javascript

Hopefully someone can point me to the right direction. I read up on waiting for functions to complete before continuing and I resolved myself to using await/async but I am just stuck now.
I tried to get the Async/Await process to work, tried to inject the await in various locations, with adjusting the functions to be async, but i can not get the PSA_Resultbody to return to the original request. Any pointers would be appreciated.
Thank you,
CE
PSA_Resultbody = ProcessPSAAPI(xmlpackage, PSA_Action);
console.log("3 - Returned data:" + PSA_Resultbody);
calls the below:
async function ProcessPSAAPI(xmlpackage, PSA_Action) { //psa action is part of the options
var options = {...};
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log('0 - Start '+body.toString());
if(res.statusCode != 200) {
PSA_Resultcode = "Error: " +res.statusCode +" - "+ res.statusMessage;
} else {
PSA_Resultcode = "Success: " +res.statusCode +" - "+ res.statusMessage;
PSA_Resultbody = ParseResults(body.toString()); //parse the results for later use --SCRIPT NEEDS TO WAIT FOR RESULTBODY TO COMPLETE
console.log("1 -PSA_Resultbody as part of RES = "+PSA_Resultbody);
}
});
res.on("error", function (error) {
console.error(error);
PSA_Resultcode = res.statusCode +" - "+ res.statusMessage;
});
});
console.log('2 -RESULT BODY BEFORE SENDING BACK TO INITIATING FUNCTION: '+PSA_Resultbody);
req.write(xmlpackage);
req.end();
return PSA_Resultbody;
Based on the above, my console log order is: 3,2,0,1 in stead of 0,1,2,3.
0 and 1 will have the correct data, so the API Call does work, but 2 will be "undefined" and should have the same data that is in 1.
There's no way to await an event emitter, so using async in this case isn't going to be useful. You cannot "return" from inside an event either.
The solution here is to return a new custom promise and to use resolve() inside of the "end" event of your emitter.
It will look something like this:
function ProcessPSAAPI(xmlpackage, PSA_Action) {
return new Promise( (resolve, reject) => {
// other code
res.on("end", function (chunk) {
// other code
resolve(PSA_Resultbody);
});
res.on("error", function (error) {
// other code
reject(error);
});
});
}
Here's a quick tutorial on creating your own promises, which I've written to simplify comprehension of the subject (official docs are somewhat dry and complex imho).
I did not change your code. I just put the appropriate promise structure in to get you started. This should really be a lesson in promises. async await is a shorthand promise structure. A Promise is one way you wait on code. It can be thought of as an array of callbacks that will be executed when the Promise is resolved.
A simple promise works like this:
const myPromise = new Promise(function(resolve, reject) {
/* Your logic goes in here. It can be anything.
* But the important part to remember is that when you have success, resolve it.
* When you have a failure, reject it.
*/
someCallBackPattern(function(error, data) {
if(error) {
reject(error);
} else {
resolve(data);
}
});
});
// To get the data out you use 'then', and 'catch'. then has two arguments.
myPromise.then(function(data) {
// The first argument is the result from resolve.
}, function(err) {
// The second argument is the result from reject.
}).catch((err) => {
// you can also get to the error from the catch callback
});
This is kinda messy and complex. So there is async await.
async function() {
try {
const result = await myFunctionThatReturnsAPromise();
// result is the resolved data
} catch (err) {
// err is the rejected Error
}
}
function myFunctionThatReturnsAPromise() {
return new Promise((resolve, reject) => {
// your code
})
}
And thats how it works.
async function someFunction () { // You can not wait on results unless you are in an await function
PSA_Resultbody = await ProcessPSAAPI(xmlpackage, PSA_Action); // await on your results.
console.log("3 - Returned data:" + PSA_Resultbody);
}
function ProcessPSAAPI(xmlpackage, PSA_Action) { // This does not need to be async. Unless you are awaiting in it.
return new Promise((resolve, reject) => { // async await is a shorthand promise structure. Although you do not need to use promises. It really helps to get the structure correct.
var options = {...};
var req = https.request(options, function (res) {
var chunks = [];
res.on("data", function (chunk) {
chunks.push(chunk);
});
res.on("end", function (chunk) {
var body = Buffer.concat(chunks);
console.log('0 - Start '+body.toString());
if(res.statusCode != 200) {
PSA_Resultcode = "Error: " +res.statusCode +" - "+ res.statusMessage;
reject(new Error(PSA_Resultcode)); // Reject you errors
} else {
PSA_Resultcode = "Success: " +res.statusCode +" - "+ res.statusMessage;
PSA_Resultbody = ParseResults(body.toString()); //parse the results for later use --SCRIPT NEEDS TO WAIT FOR RESULTBODY TO COMPLETE
console.log("1 -PSA_Resultbody as part of RES = "+PSA_Resultbody);
resolve(PSA_Resultbody); // Resolve your result
}
});
res.on("error", function (error) {
console.error(error);
PSA_Resultcode = res.statusCode +" - "+ res.statusMessage;
reject(new Error(PSA_Resultcode)); // Reject you errors
});
});
console.log('2 -RESULT BODY BEFORE SENDING BACK TO INITIATING FUNCTION: '+PSA_Resultbody);
req.write(xmlpackage);
req.end();
})
}

Asynchronous Method In JavaScript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
Below is my JS Method
function test(key, language) {
var uri = '/Resources/ValidationMessages.json';
fetch(uri).then(response => {
return response.json();
}).then(data => {
console.log('Inside Function - ' + data[key]);
return data[key];
}).catch(err => {
console.log(' Error ');
});
}
And after calling this method as
var v = test('spnrequiredRegisterEmail');
console.log('Outside Function - ' + v);
Inside the function it print value but Outside Function statement is always undefined.
The solution that I am trying to achieve is that I have to set some text in n number of span as inner text, which will come through this function call after passing the respective key, but every span displays undefined as inner text
It won't wait for a method to finish , so how can I solve this issue?
Try using async / await
async function test(key, language) {
try {
var uri = '/Resources/ValidationMessages.json';
var resp = await fetch(uri);
var data = resp.json();
console.log('Inside Function - ' + data[key]);
return data[key];
catch(err) {
console.log(err);
}
}

Recursive async/await request doesn't return to calling function

I'm doing a recursive request with async/await whenever the received response has length === 0. The problem is that when some request returns the desired data, the resolve(data); part of the promise doesn't seem to work.
So, in my code, I have reached the point where I get to make multiple recursive calls and, finally, receive a response whose length is not 0.
Note: there are plenty of API keys published in Github if you want to test the code.
var apiKey = "yourApiKey";
var url = "https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=";
function requestData(url) {
return fetch(url).then(response => {
if(response.ok) {
return response.json().then(data => {
return Promise.resolve(data);
});
} else {
return Promise.reject(response.status);
}
});
}
function NasaRequest(sun, limit, frecuency) {
return new Promise(async (resolve, reject) => {
var data = await requestData(url + sun + "&api_key=" + apiKey);
if(data.photos.length === 0 && !limit) {
setTimeout(async () => {
console.log("Delay for next request (sun " + sun + "): ", frecuency);
return await NasaRequest(sun - 1, limit, frecuency);
}, frecuency);
} else {
console.log("Resolve data:", data); // Code acutally reaches this point
resolve(data); // But this doesn't seem to work
}
});
};
async function init() {
try {
const currentValue = await NasaRequest(2175, false, 2000);
console.log("currentValue:", currentValue); // I want to reach this point, but is like the promise never returns
}catch(err){
console.error(err);
}
}
init();
In that moment, I want to return the data in the response to the calling init() function, for what I use resolve(data);. But it doesn't seem to work.
What am I doing wrong?
The problem is on setTimeout. When you calling setTimeout it returns right away and implicitly return undefined. The subsequence return doesn't matter at that point. If all you want to do, is to pause, and then proceed try something like this
async function requestData(url) {
var response = await fetch(url);
if (response.ok) {
return response.json()
} else {
throw new Error(response.status);
}
}
function sleep(ms) {
return new Promise((resolve) => {
setTimeout(resolve, ms);
});
}
async function nasaRequest(sun, limit, freq) {
var data = await requestData(url + sun + "&api_key=" + apiKey);
if (data.photos.length === 0 && !limit) {
await sleep(freq);
console.log("Delay for next request (sun " + sun + "): ", freq);
return await nasaRequest(sun - 1, limit, freq);
} else {
console.log("Resolve data:", data);
return data;
}
};
async function init() {
try {
const currentValue = await nasaRequest(2175, false, 2000);
console.log("currentValue:", currentValue);
} catch (err) {
console.error(err);
}
}
init();
I added a simple sleep function to handle the pause. I also modified requestData (removed then and Promise parts).
Note that using this recursive approach you may run into stack overflow. To avoid that problem you can simply use a loop and check against your limit variable.

return new Promise never returns [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I'm trying to use a promise in my function but it never returns. This is my code:
function getData(id) {
return new Promise(function(resolve, reject) {
DbUtil.connection.query("my query... ", [id],
function (error, results, fields) {
if (error) {
reject(error);
} else {
resolve(results);
}
}
);
})
}
The query works and I can see its results in the else block. But the function itself doesn't return. I tried adding a return statement after the resolve, and also after the Promise function itself. But it still doesn't return.
What am I missing?
EDIT: how do I know the function doesn't return? Because
function main() {
var data = getData(1);
console.log("data returned? " + data);
}
in the above main function the log statement is never called.
It's not the proper way to handle a promise
Try this:
var data;
getData(1).then(function(d) {
console.log(d);
data = d;
});
// Since a Promise is async, you can't log data here
or
async function main() {
var data = await getData(1);
console.log(data);
}
Note that this examples does not handle catch case.

Providing previous values of promises

My question involves promises and providing previous values of chain promises. The question is, is the item passed from first return promise to second promise "runItem --> testItem"?
Or do we have to pass the item through all promises?
Example:
db.items.find({_id: id}).then(function (res) {
runItem(item);
})
function runItem(item) {
removeFromQueue(item.id).then(function () {
testItem(item);
});
}
function testItem(item) {
...
}
function removeFromQueue(item) {
return db.queue.remove({_id: item._id});
}
EDIT:
Maybe this would be a better example:
Can we access original attribute item, or is it going to be overwritten when the next time function is called?
function start(id)
db.find({_id: id}).then(function (item) {
test(item).then(function (res) {
// can we access original attribute item, or is it going to be overwritten when the next time function is called
resolve({ res: res, item: item });
});
});
}
function test(item) {
return $test(item).then(function () {
resolve('success');
});
}
You can change the return value of a previous promise and simply return it. The next promise will be influenced. Check this example:
var promise = new Promise(function(res,rej){ res({data: 7}) }); // start with {data:7}
var promise1 = promise.then(function(res){ console.log('promise.then: ' + JSON.stringify(res)); return res.data; }); // log: {data:7}. return: 7
var promise2 = promise1.then(function(res) { console.log('promise1.then : ' + res); return res + 1;}); // log:7. return 8.
var promise3 = promise2.then(function(res) { console.log('promise2.then: ' + res); return res;}); // log:8. return 8.
var promise4 = promise3.then(function(res) { console.log('promise3.then: ' + res); return res;}); // log:8. return 8.
Try Promise.props function.
Something like
...
{
...
return Promise.props({res: res, item: item}).
.then(function(result){
return Promise.resolve({ res: res, item: item });
});
}
The example you have posted doesn't returns promise object .
Below is an example for the chaining things in promise, have a look.
functionA = function(text) {return new Promise(function(resolve) {
resolve(text);
console.log(text + " at function A");
});
}
functionB = function(text) {return new Promise(function(resolve) {
resolve(text);
console.log(text + " at function B");
});}
functionA("test").then(function (res)
{
console.log(res + " at then");
runItem(res);
})
function runItem(item) {
functionB(item).then(function (res) {
console.log(res + " at Function Run Item");
testItem(res);
});
}
function testItem(item) {
console.log(item + " at Function testItem");
}
in the above example you can see the runItem(item)'s item is passed to promiseobject of functionB, which wen resolved returns the same in then as res, which is further used by testItem(res).
if you want to do any operation on runItem(item)'s item you can modify it before the promise is resolved for FunctionB

Categories