Im new to Nodejs and was wondering why the functions execute out of order instead of how ive written it:
var tor_proxy = require("tor-request")
var s = require("sleep");
tor_proxy.setTorAddress("localhost", 9050);
tor_proxy.TorControlPort.password = "password";
function ShowIP() {
tor_proxy.request("http://ident.me", function(err, response, body) {
if(!err && response.statusCode == 200) {
console.log(body);
}
});
}
function Renew() {
tor_proxy.renewTorSession(function() { console.log("renewed"); });
}
ShowIP();
Renew();
ShowIP();
//Id Like It To Show The IP Then Renew Then Show The New IP
//But Instead It's Out Of Order
Nodejs is event driven (correct me if im wrong) and any help will be appreciated. Thanks :)
The script will be executed like this:
Inside ShowIP(), tor_proxy.request() sends a request to http://ident.me .
Without waiting for any reply from http://ident.me, function Renew() is executed.
tor_proxy.renewTorSession() is likely to be an asynchronous function. If so, after it begins, the next ShowIP() will be executed without waiting for renewTorSession() to complete.
Depending on how fast http://ident.me replies and how fast renewTorSession() completes, the results may vary.
To execute these functions in proper order, you can search for the following keywords:
Promise
Async/Await
util.promisify() from Node.js
Libraries like Async.js
An example using promise, async and await:
var tor_proxy = require('tor-request');
tor_proxy.setTorAddress('localhost', 9050);
tor_proxy.TorControlPort.password = 'password';
function ShowIP() {
return new Promise((resolve, reject) => {
tor_proxy.request('http://ident.me', function (err, response, body) {
if (err) reject(err);
else if (response.statusCode !== 200) reject('response.statusCode: ' + response.statusCode);
else {
console.log(body);
resolve();
}
});
});
}
function Renew() {
return new Promise((resolve, reject) => {
tor_proxy.renewTorSession(() => {
console.log('renewed');
resolve();
});
});
}
async function testFunction() {
// Await makes sure the returned promise completes before proceeding.
// Note that await keyword can only be used inside async function.
try {
await ShowIP();
await Renew();
await ShowIP();
console.log('done!');
} catch (error) {
console.log(error);
}
}
testFunction();
Related
so I currenlty know what the issue is, it's the fact that my await here var contacBID = await ContactIDFinder.findingBoondIDcontact(ContactHID) can not be used here. But he problem is: I need to wait in order to avoid just getting a promise, and this has to include a Promise since it will also be used later with a promise. Any ideas? Feel free to call my code ugly, I know it is, but any help is appreciated, thanks!
var optionsA = {
method: "GET",
url: "https://example.com",
qs: { hapikey: "smthng" }
};
return new Promise(function(resolve, reject){
request(optionsA, function (error, response, body) {
if(error){
logResponse("could not reach boondmanager status:",response.statusCode);
reject("error while reading");
}
else{
var dealH = JSON.parse(body);
if(dealH.associations.associatedVids[0] != undefined){
var ContactHID = dealH.associations.associatedVids[0]
var contacBID = await ContactIDFinder.findingBoondIDcontact(ContactHID)
console.log(`attempt at finding the BID for the contact linked to the company led to : ${contacBID}`)
if (contacBID != null) {
console.log("associated BID is : "+ contacBID)
}
else{
console.log("linked with a contact unsynchronized")
}
}
else{
console.log("Not linked at all with a contact")
resolve(null)
}
resolve(contacBID);
}
});
});
}```
You can use await there if you mark the enclosing function as async.
Change:
request(optionsA, function (error, response, body) {
to:
request(optionsA, async function (error, response, body) {
Today, when I was working with node, I met some special async functions with "overloads" that accept both promises and callbacks. Like this:
doSomething(result => {
console.log(result)
})
doSomething()
.then(result => console.log(result))
And probably this:
const result = await doSomething()
console.log(result)
I tried to implement this in my code but was unsuccessful. Any help would be appreciated.
You can make a function like this by creating a promise, then chaining on that promise with the argument if there is one, and then returning that chained promise. That will make it call the callback at the appropriate time, as well as giving you access to the promise that will complete when the callback completes. If you want the original promise even when there's a callback (not the chained version), then you can return that instead, by still chaining but then returning the original promise instead.
function f(cb) {
let promise = new Promise((resolve, reject) => {
setTimeout(() => resolve(123), 1000);
});
if (cb) {
return promise.then(cb);
} else {
return promise;
}
}
// usage 1
f(console.log)
// usage 2
f().then(console.log)
Let's say you had a function that was going to read your config file and parse it and you wanted to support both versions. You could do that like this with two separate implementation inside. Note, this has full error handling and uses the nodejs calling convention for the callback that passes parameters (err, result):
function getConfigData(filename, callback) {
if (typeof callback === "function") {
fs.readFile(filename, function(err, data) {
try {
if (err) throw err;
let result = JSON.parse(data);
callback(null, result);
} catch(e) {
callback(err);
}
});
} else {
return fs.promises.readFile(filename).then(data => {
return JSON.parse(data);
}).
}
}
This could then be used as either:
getConfigData('./config.json').then(result => {
console.log(result);
}).catch(err => {
console.log(err);
});
configData('./config.json', (err, data) => {
if (err) {
console.log(err);
} else {
console.log(data);
}
});
Depending upon the specific asynchronous operation, it may be better or more efficient to have two separate implementations internally or to have one implementation that you adapt at the end to either a callback or a promise.
And, there's a useful helper function if you adapt a promise to a callback in multiple places like this:
function callbackHelper(p, callback) {
if (typeof callback === "function") {
// use nodejs calling convention for callbacks
p.then(result => {
callback(null, result);
}, err => {
callback(err);
});
} else {
return p;
}
}
That lets you work up a simpler shared implementation:
function getConfigData(filename, callback) {
let p = fs.promises.readFile(filename).then(data => {
return JSON.parse(data);
});
return callbackHelper(p, callback);
}
I want to send my response when I executed my for loop but it is sending directly without wait in for loop
I have tried with different way and apply wait in async function but it goes to next
async (request, response) => {
let imageErr = [],
succArr = [];
/** Image processing and send to s3 */
const OriginalUrl = request.body.images;
for (const image of OriginalUrl) {
await createImage.createWebp(image, 'webp', (err, result) => {
if (err) {
imageErr.push(err);
} else {
succArr.push(result);
console.log(succArr);
}
});
/** webp */
await createImage.createJpeg(image, 'jpeg', (err, result) => {
if (err) {
imageErr.push(err);
} else {
succArr.push(result);
console.log(succArr);
}
});
}
if (succArr === 12) responseUtil.success(response, succArr);
else responseUtil.error(response, 'Fail');
};
I expect send response after the for loop is fully executed
It seems you use the kind of framework that accepts a callback instead of returning a Promise (which is necessary for await to work properly). One way is to wrap your call into a Promise. Try something like this:
for (const image of OriginalUrl) {
await new Promise((res, rej) => {
createImage.createWebp(image, 'webp', (err, result) => {
if (err) {
imageErr.push(err);
} else {
succArr.push(result);
}
res(); // <-- Important
});
});
(...)
}
You may also utilize rej but then you would have to catch it as an exception. Your choice.
Side note: if (succArr === 12), did you mean if (succArr.length === 12)? Also, I assume this is for debug, because it definitely is not a good idea to hardcode literal 12.
I am using the libraries mongoose 5.4.20, request 2.88.0, q 1.5.1, and deasync 0.1.14.
When using .cursor() and .eachAsync() the promises don't get resolved in the order I would expect. In particular, I make a request to the data base, and for each returned document, I make several external requests via an async series. The sample code is as follows:
Request Promise:
function Request (options) {
const result = Q.defer();
request(options, function (error, response, body) {
if (error) {
result.reject(error);
} else {
result.resolve(body);
}
});
return result.promise;
}
Async Series Promise:
function Series (entry) {
const result = Q.defer();
const errors = [];
//Iterate over some given array
async.eachSeries(array, function (doc, cb) {
//Make some async request
return Request(doc)
.then(function (body) {
//do stuff with 'body' and 'entry'
})
.then(function () {
//Move to the next doc in 'array'
return cb(null);
})
.fail(function (err) {
//Handle errors
errors.push(err);
//Move to the next doc in 'array'
return cb(null);
});
}, function (err, results) {
if (err) {
errors.push(err);
}
if (errors.length !== 0) {
result.reject(errors);
} else {
console.log('A');
result.resolve();
}
});
return result.promise;
}
Mongoose:
mongooseModel
.find()
.cursor()
.eachAsync(entry => Series(entry))
.then(function () {
console.log('B');
}, function (err) {
console.log(err);
});
What confuses me is that the final callback in .then() after .eachAsync() seems to be called before the promise in .eachAsync() is resolved, i.e. 'console.log('B')' is called before 'console.log('A')'. I would have expected, that .eachAsync() will wait until the promise is resolved, then pulls the next document from the collection and so on, and only at the very end, when all promises are resolved, the final .then() is called.
Any suggestion as to what I am doing wrong would be greatly appreciated. Thanks.
One thing puts me off with Promise is that it is difficult to grasp with resolve and reject. Also the need of wrapping for Promise is ugly. Unless you use it very often, I tend to forget how to use them over time. Besides, code with Promise is still messy and hard to read. Hence I don't really like using it at all - because it has not much different from the callback hell. So I thought with ES7 await, I can avoid using Promise and giving me some more faith in JavaScript, but it seems that it is not the case. For instance:
const getOne = async () => {
return Weather.findOne(options, function(err, weather) {
//
});
}
const getWeather = async () => {
const exist = await getOne();
if (exist == null) {
return new Promise(function(resolve, reject) {
// Use request library.
request(pullUrl, function (error, response, body) {
if (!error && response.statusCode == 200) {
// Resolve with the data.
resolve(body);
} else {
// Reject with the error.
reject(error);
}
});
});
}
}
const insertWeather = async () => {
try {
const data = await getWeather();
} catch (err) {
res.set('Content-Type', 'application/json');
return res.status(200).send('Error occurs: ' + err);
}
}
insertWeather();
request(pullUrl, function (error, response, body) {} is an AJAX call from request package for nodejs.
I have to wrap it with Promise - but not precede it with await. Ideally this is what I imagine:
return await request(pullUrl, function (error, response, body) {...}
But if I do that, I will get the request object in return, instead of the data return from the request package - at this line:
const data = await getWeather();
Any ideas or solutions to avoid using Promise in the case such as the one above?
You'll find bluebird and node.js now come with promisify to allow you to consume Node callbacks as promises when you need too. Alternatively, you can consider a functional reactive approach and use a library like RxJS which will handle promises, node callbacks and other data types into streams.
const promisify = require('utils').promisify // alternatively use bluebird
const request = require('request-promise');
const weatherFn = promisify(Weather.findOne);
const weatherOptions = {};
async function getWeatherIfDoesNotExist() {
try {
const records = await weatherFn(weatherOptions);
if (records === null) {
return await request('/pullUrl');
}
} catch(err) {
throw new Error('Could not get weather');
}
}
async function weatherController(req, res) {
try {
const data = await getWeatherIfDoesNotExist();
} catch (err) {
res.set('Content-Type', 'application/json');
return res.status(200).send('Error occurs: ' + err);
}
}
function altWeatherController(req, res) {
return getWeatherIfDoesNotExist()
.then((data) => { // do something })
.catch((err) => {
res.set('Content-Type', 'application/json');
return res.status(200).send('Error occurs: ' + err);
})
}
As mentionned in the documentation here, you will need to wrap request with interfaces wrappers like request-promise (or you can find alternatives interface in the documentation) in order to return a Promise from request.