I have the program below:
const request = require('request');
var res = {};
process.env['NODE_TLS_REJECT_UNAUTHORIZED'] = 0
res = adpost();
//console.log(res.body);
console.log(res.body);
async function adpost() {
var postResponse = await Post();
return postResponse;
}
async function Post() {
const options = {
url: "xxx",
form: {
'usenumber': ''
}
};
return new Promise((resolve, reject) => {
request(options, (error, response, body) => {
if (error) {
return resolve({
body,
error
});
}
return resolve({
body,
response
})
});
})
}
As it returns the promise, I tried to call in another async function as well. I always get a pending promise or undefined. How will I get the actual value?
adpost is an asynchronous function. It takes some time to run, does not return immediately, and the code does not wait for it to return before continuing executing statements. res = adpost(); does not wait for the request to finish before assigning the value. You can't make synchronous code (like the top level of your file, where res = adpost(); is) grab asynchronous results.
You must use a callback or another asynchronous function. There isn't a way to get the response body up into synchronous context, you can only pass around a Promise or a callback that will be resolved/executed when the response body is available.
const request = require('request');
adpost().then(res => {
console.log(res.body);
});
Related
I am new to await/async in Jquery. When I am trying to use it in my js file, It is getting executed, but not as expected.
async updateProduct (product) {
product.travelers.forEach((traveler, travelerOrder) => this.updateProductwithPassengerName(traveler) )
return product
}
async updateProductwithPassengerName (traveler) {
const travelerId = traveler.profile_id;
var body = await this.userServiceClient.request('/v2/users/' + travelerId + '/info','GET')
traveler.first_name = body.first_name
traveler.last_name = body.last_name
return traveler
}
async request (path, method, body) {
const options = {
method: method,
body: body,
headers: this.headers(),
credentials: 'same-origin'
}
const response = await fetch(this.relativeUrl(path), options)
if (!response.ok) {
throw new HttpError('Technical error occured', response.status)
}
return response.json().catch(function () {
throw new HttpError('No results found', response.status)
})
}
Those are the 3 functions. What is happening now is that
traveler.first_name = body.first_name
traveler.last_name = body.last_name
these are not setting in synchronous manner( after
var body = await this.userServiceClient.request('/v2/users/' +
travelerId + '/info','GET')
. These are executing after a quiet a long time.
What I am doing here is that, for each traveler I am setting first_name and last_name. And updating the product object. Since this setting of values is happening after a long time, product object is getting updated later, by the time UI page renders. I want this setting values to happening before doing anything else in jquery.
Looking for help
The problem is that forEach will not await the asynchronous result and so your first function returns a promise that immediately resolves, without waiting for the requests to finish.
Here is how to correct:
async updateProduct (product) {
await Promise.all(product.travelers.map((traveler, travelerOrder) => this.updateProductwithPassengerName(traveler) ));
return product
}
Or, if the backbone cannot deal with all these concurrent requests, then wait for each of them to complete before issuing the next:
async updateProduct (product) {
for (let traveler of product.travelers) {
await this.updateProductwithPassengerName(traveler);
}
return product
}
when using asyn/await in JQuery or angularjs or nodejs, use promise. Promise will complete the process and then return either success or fail. Then only execute next steps.Go through below links and you will get idea.
Modern Asynchronous JavaScript with Async and Await
async & await in Javascript
I am trying to issue an HTTP request to another web service, from a Google Cloud Function (GCF) that I have created. I need the HTTP request to complete and return that result inside of my GCF so that I can do something else with it.
My question is; What is the best way to use Promise inside a Google Cloud Function? Is what I am trying to do possible?
My code currently looks like this:
export const MyGCF = functions.https.onRequest((request, response) => {
let dayOfTheWeek: any;
const request1 = require('request');
const url = 'http://worldclockapi.com/api/json/pst/now';
function getDay() {
return new Promise((resolve, reject) => {
request1(url, { json: true }, (err: any, res: any, body: any) => {
if (err) {
return reject(err);
}
resolve(body.dayOfTheWeek);
});
});
}
getDay().then((data) => {
dayOfTheWeek = data;
console.log(dayOfTheWeek);
});
});
In general your approach will work, and you can define additional functions inside of your MyGCF handler, in the same way that you have defined getDay(). One problem with you current code however is that you're forgetting to "write a response" for the request being processed by MyGCF.
You can write a response for the request by calling send() on the second res argument of your MyGCF request handler. A simple example would be:
/* Sends a response of "hello" for the request */
res.send("hello");
With respect to your code, you can use res.send() in your .then() callback to send a response back to the client after getDay() has completed (see code below). Note also to include a .catch() clause and callback for the error case (with an error status) to ensure the client receives an appropriate error response if the call to getDay() fails:
export const MyGCF = functions.https.onRequest((req, res) => {
const request = require('request');
const url = 'http://worldclockapi.com/api/json/pst/now';
function getDay() {
return new Promise((resolve, reject) => {
request(url, {
json: true
}, (err: any, r: any, body: any) => {
if (err) {
reject(err);
} else {
resolve(body.dayOfTheWeek);
}
});
});
}
getDay().then((dayOfTheWeek) => {
/* Send a response once the getDay() request complete */
res.send(dayOfTheWeek);
})
.catch(err => {
/* Don't forget the error case */
res.status(500).send(err);
});
});
I'm having difficulty accessing the result of an asynchronous request to an rss feed. I referred to the post, How do I return the response from an asynchronous call?, which suggests using Promises. I implemented a Promise, which resolves, but still cannot access the result of the request outside the request function.
I am attempting to set the variable film to the request result, but can only seem to get undefined.
var request = require("request");
var parseString = require("xml2js").parseString;
var url = 'http://feeds.frogpants.com/filmsack_feed.xml';
var film;
request(url, function(error, response, body) {
return new Promise(function(resolve, reject) {
if (error) {
console.log(error);
}
else {
if (response.statusCode === 200) {
parseString(body, function(err, result) {
var feed = result.rss.channel[0].item.reduce(function(acc, item) {
acc.push(item);
return acc;
}, [])
resolve(feed)
})
}
}
})
.then(function(data) {
film = data;
})
})
console.log(film)
Logging feed from within the request function returns the results that I am looking for. What am I missing? Thanks.
I'm not very experienced, but I think the issue is that console.log is executed before your request (asynchronous) returns a result.
Perhaps you should try returning "film" from the last then() and chain another then() to console.log that var
...
.then(function(data) {
return film = data;
})
.then((result) => console.log(result))
})
I am performing an async request to pull data from a server and then call a function after the request. My question is how do I ensure the request is complete and all data loaded before processRecords() runs?
Thanks in advance.
function getRecords () {
var ids = Server.getIds();
var allTheRecords = [];
ids.forEach(function(recordId) {
Server.getRecord(recordId, function (error, data) {
if(error) {
console.log(error);
} else {
allTheRecords.push(data);
};
});
});
processRecords(allTheRecords);
}
How are you performing the Asynchronous request? If it's an AJAX request, the API provides for callbacks to be supplied based on the result of the call.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
You could use the native Promise api to perform the async actions for you.
Using Promise.all you can give it an array of promises that need to be resolved before calling the processRecords function.
It also now more reusable as you have a getRecord function that you could use elsewhere in your code.
You should probably think of a way to add in the ability to get multiple records from the server if you control it though. You don't really want to fire off a bunch of network requests if you can do it in just one.
// Server mock of the api you have shown
const Server = {
getRecord(id, callback) {
console.log('getRecord', id)
callback(null, {id})
},
getIds() {
return [1, 2, 3]
}
}
function getRecords (ids, processRecords) {
console.log('getRecords', ids.join())
// mapping the array of id's will convert them to an
// array of Promises by calling getRecord with the id
Promise.all(ids.map(getRecord))
// then is called once all the promises are resolved
.then(processRecords)
// this will be called if the reject function of any
// promise is called
.catch(console.error.bind(console))
}
function getRecord(recordId) {
// this function returns a Promise that wraps your
// server call
return new Promise((resolve, reject) => {
Server.getRecord(recordId, function (error, data) {
if(error) {
reject(error)
} else {
resolve(data)
}
})
})
}
getRecords(Server.getIds(), function(records) {
console.log('resolved all promises')
console.log(records)
})
In my code below, 5 always prints before 4. I thought because the callback to postUsers was in a return statement from matchAgainstAD it would wait for the for loop and ad lookup to complete before returning. How can I do this in the most simple way?
var matchAgainstAD = function(stUsers) {
stUsers.forEach(function (element, i) {
var sAMAccountName = stUsers[i].guiLoginName;
// Find user by a sAMAccountName
var ad = new ActiveDirectory(config);
ad.findUser(sAMAccountName, function(err, user) {
if (err) {
console.log('ERROR: ' +JSON.stringify(err));
return;
}
if (!user) {
staleUsers.push(stUsers[i])
console.log(4)
}
// console.log(staleUsers);
});
})
return postUsers(staleUsers)
}
var postUsers = function(staleUsers) {
console.log(5);
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost:8000/api/record/newRecord',
qs: staleUsers
}, function(err, res, body) {
// console.log(body);
})
}
matchAgainstAD();
This is very classic asynchronous problem in node.js. Your findUser() function has an asynchronous response which means the callback is called sometime later. Meanwhile, the rest of your loop continues to run so that all the requests are in-flight at the same time and then the responses start coming in sometime later. Thus, you can't call postUsers() after matchAgainstAd() returns because the inner async operations are not yet completed and thus staleUsers is not yet populated.
There are multiple approaches to solving this problem. In general, it is worth learning how to use promises for operations like this because they offer all sorts of very useful flow of control options when using asynchronous operations and node.js does pretty much all I/O operations as async. But, to best illustrate what's going on in this type of issue, I'll first show you a manually coded solution. In this manually coded solution, you keep track of how many operations are still remaining to complete and when all have completed, then and only then, do you call postUsers() with the accumulated data.
Manually Coded Solution
var matchAgainstAD = function (stUsers) {
var remaining = stUsers.length;
stUsers.forEach(function (element, i) {
var sAMAccountName = stUsers[i].guiLoginName;
function checkDone() {
if (remaining === 0) {
postUsers(staleUsers);
}
}
// Find user by a sAMAccountName
var ad = new ActiveDirectory(config);
ad.findUser(sAMAccountName, function (err, user) {
--remaining;
if (err) {
console.log('ERROR: ' + JSON.stringify(err));
checkDone();
return;
}
if (!user) {
staleUsers.push(stUsers[i])
}
checkDone();
});
});
}
var postUsers = function(staleUsers) {
request.post({
headers: {'content-type' : 'application/x-www-form-urlencoded'},
url: 'http://localhost:8000/api/record/newRecord',
qs: staleUsers
}, function(err, res, body) {
// console.log(body);
})
}
The core logic here is that you initialize a counter to the number of operations that will be carried out. Then, in your loop where each operation is happening, you decrement the remaining counter anytime one of the operations completes (calls it's completion callback). Then, after processing the result (in both the success and error code paths), you check if the remaining count has reached 0 indicating that all requests are now done. If so, then the staleUsers array is now fully populated and you can call postUsers(staleUsers) to process the accumulated result.
Solution Coded Using Bluebird Promises
The idea here is that we use the control flow logic and enhanced error handling of promises to manage the async control flow. This is done by "promisifying" each asynchronous interface we are using here. "promisifying" is the process of creating a small function wrapper around any async function that follows the node.js calling convention where the last argument to the function is a callback that takes at least two arguments, the first an error and the second a value. This can be automatically turned into a wrapper function that returns a promise, allow using to use promise logic flow with any normal async operation.
Here's how this would work using the bluebird promise library.
var Promise = require('bluebird');
var request = Promise.promisifyAll(request('require'));
var matchAgainstAD = function (stUsers) {
var staleUsers = [];
var ad = new ActiveDirectory(config);
// get promisified version of findUser
var findUser = Promise.promisify(ad.findUser, ad);
return Promise.map(stUsers, function(userToSearchFor) {
var sAMAccountName = userToSearchFor.guiLoginName;
return findUser(sAMAccountName).then(function(user) {
// if no user found, then consider it a staleUser
if (!user) {
staleusers.push(userToSearchFor);
}
}, function(err) {
// purposely skip any requests we get an error on
// having an error handler that does nothing will
// stop promise propagation of the error (it will be considered "handled")
});
}).then(function() {
if (staleUsers.length) {
return postUsers(staleUsers);
}
return 0;
});
}
var postUsers = function (staleUsers) {
return request.postAsync({
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
url: 'http://localhost:8000/api/record/newRecord',
qs: staleUsers
}).spread(function (res, body) {
// console.log(body);
return staleUsers.length;
})
}
matchAgainstAD(users).then(function(qtyStale) {
// success here
}, function(err) {
// error here
})
Standard ES6 Promises Version
And, here's a version that uses only the standard ES6 promises built-into node.js. The main difference here is that you have to code your own promisified versions of the async functions you want to use because you can't use the built-in promisify capabilities in Bluebird.
var request = request('require');
// make a promisified version of request.post
function requestPostPromise(options) {
return new Promise(function(resolve, reject) {
request.post(options, function(err, res, body) {
if (err) {
reject(err);
} else {
resolve([res, body]);
}
});
});
}
// make a function that gets a promisified version of ad.findUser
function getfindUserPromise(ad) {
return function(name) {
return new Promise(function(resolve, reject) {
ad.findUser(name, function(err, user) {
if (err) {
reject(err);
} else {
resolve(user);
}
});
});
}
}
var matchAgainstAD = function (stUsers) {
var staleUsers = [];
var promises = [];
var ad = new ActiveDirectory(config);
// get promisified version of findUser
var findUser = getFindUserPromise(ad);
stUsers.each(function(userToSearchFor) {
promises.push(findUser(userToSearchFor.guiLoginName).then(function(user) {
// if no user found, then consider it a staleUser
if (!user) {
staleusers.push(userToSearchFor);
}
}, function(err) {
// purposely skip any requests we get an error on
// have an error handler that does nothing will
// stop promise propagation of the error (it will be considered "handled")
}));
});
return Promise.all(promises).then(function() {
if (staleUsers.length) {
return postUsers(staleUsers);
}
return 0;
});
}
var postUsers = function (staleUsers) {
return requestPostPromise({
headers: {
'content-type': 'application/x-www-form-urlencoded'
},
url: 'http://localhost:8000/api/record/newRecord',
qs: staleUsers
}).then(function (err, results) {
var res = results[0];
var body = results[1];
// console.log(body);
return staleUsers.length;
})
}
matchAgainstAD(users).then(function(qtyStale) {
// success here
}, function(err) {
// error here
})
ad.findUser takes a callback that contains the console.log(4). That function is async, and will hit your callback when the IO operation has completed.
On the other hand, postUsers is called completely synchronously, so it will hit console.log(5) before ad.findUser enters your callback.
A simple way to fix this is to call postUsers from inside of your ad.findUser callback.
I would suggest looking into the promise pattern for JavaScript to manage dependencies between async operations. There are several popular libraries (Q and RSVSP.js being a couple of them).