node js postgres assign value to variable outside scope of then - javascript

I have to compare few rows derived from potgres with data derived from the dynamo DB. problem is in both cases i have to iterate over data & unless i can assign the value to a variable i will have to query the same data again from either one of two databases.
function postgressdata(sql){
return new Promise(function(resolve, reject) {
client_postgres.query(sql, (err, res) => {
resolve(res);
});
});
}
let get_creatives = postgressdata(sql);
get_creatives.then(function(result) {
console.log(result); // prints the result
let new_result = result;
}
console.log(new_result) // does not print result
How Can I assign the data to a variable here & use it anywhere?
I am a newbie to NODEJS so pardon me if I am asking silly question.

Nodejs is non-blocking.
so when this block of code runs
let get_creatives = postgressdata(sql);
get_creatives.then(function(result) {
console.log(result); // prints the result
let new_result = result;
}
console.log(new_result) // does not print result
what will happen is you will get nothing printed first because .then() will be called when the promise is resolved so this line
console.log(new_result) // does not print result
will be executed first which doesn't have the value yet obviously.
after that when the promise is resolved .then will be called and your value will be set.
now how to solve this?
I am assuming you're sending the value back to the callee so you can either use the async/await structure or you can use a callback, depending on how you need the value.

You can just keep a reference to the promise as your cache. A promise in JavaScript represents the result of an async operation, not the operation itself.
If you have something like:
async function runQuery() {
const result = await db.query(sql`SELECT * FROM creatives;`);
console.log('ran query');
return result;
}
const creativesPromise = runQuery();
async function useResult() {
console.log(await creativesPromise);
}
useResult();
useResult();
useResult();
even though we use the resulting list of creatives three times, "ran query" will only get logged once. Every use of the query results will need to be async, because you never know whether the query has finished running when you request the data, but the query will only be run once.

Related

Repeatedly call a function that returns a promise until one of them contains a specific response

Hello I need to call a REST function with an ID, that returns a promise in React.js. This function will at some point contain a certain value in its response when called . Until another service has processed an initial request this value will be null.
This is what I have done so far:
while(myVariable){
myfunction(myID).then( (response) => {
if(response['value'] != null
myVariable = false;
}
});
}
The problem with this code is that the while loop is called as fast as possible and thus completely utilises the computer. So I need a function that allows me to poll for a result by an ID until the response of one of the function calls contains a valid response.
I have tried the following method but without success, because I don't have a fixed number of runs:
Wait promise inside for loop
Thanks in regards.
As you state, the problem is that the while loop runs eagerly, not waiting for each promise to resolve.
One way to solve that is to use recursion. Recursion gives you more control over when exactly you want to 'loop' next:
let getValue = () => {
myFunction(myID).then(response => {
if (response['value'] === null) {
setTimeout(getValue);
} else {
// here you know the other service has processed the initial request
}
});
};
First I wrapped the whole thing in a function called getValue. Note that this function is only called again after the promise resolves. (The call to setTimeout is a trick to use recursion without consuming the stack.) If this still runs too quickly, pass an additional parameter of 100 or so to the setTimeout invocation.
Alternatively, you may be able to use async/await similarly to the link you shared. I'm no expert on async/await but it should work the same with while loops as with for loops, judging by this and this.
You can use the async function with await.
I also use a delay function to delay each call to the myfunction().
While you get a response, you can break the while loop.
const delay = ms => new Promise((resolve, reject) => setTimeout(resolve, ms));
async function main() {
const myID = 1;
let response;
while (true) {
response = await myfunction(myID);
if (response["value"] != null) {
break;
}
await delay(5000);
}
//do Something once you get the response here below:
}
main();

How can I declare a variable and assign it to dollar's current rate?

I am trying to write a website that gets an number input from the user as TRY (Turkish currency) and converts it to dollar. I want to do this with fetch() in js. Here is my code. If I write console.log(data.tr.rate) instead of rate = data.tr.rate, it prints dollar's current rate which exactly what I want, however when I write the code below it prints "undefined".
var rate;
const m_currency = fetch('http://www.floatrates.com/daily/usd.json').then(res => res.json()).then(function(data){
rate = data.tr.rate;
});
console.log(rate);
The code where you request the rates JSON is a Promise, which is asynchronous code. You should execute all your code inside the then block, anything you do outside that block, may execute earlier, so the value of the variable cannot be told.
If you want to fetch synchronously to assign to a variable, you may use an async function and await the resolution of the Promise, but async functions are Promises themselves, that you must run as the fetch function. Here's an example:
async function get_rate() {
var res = await fetch('http://www.floatrates.com/daily/usd.json');
var data = await res.json();
return data.tr.rate;
};
// works
get_rate().then((rate) => { console.log(rate); });
// doesn't work, no error but it's a promise and not a value
console.log(get_rate());
The fetch API is asynchronous, this means that the console.log will occur before your fetch sends a response back.
var rate; // First
const m_currency = fetch('http://www.floatrates.com/daily/usd.json').then(res => res.json()).then(function(data) {
rate = data.tr.rate; // Third
});
console.log(rate); // Second

Question about node-cache object changing to a resolved promise after assigning its value to a constant

I'm trying to wrap my head around Nodejs and Promises and I'm seeing a behavior I don't quite understand so I'd like to get some help from the experts :)
I have trainStations.js file that returns information and caches it using node-cache library.
async function getTrainStations(){
var stations = await knex.select()
.from('TrainStations')
stations.forEach(
item => cache.set(item['code'], item['name'])
);
knex.destroy();
return cache;
}
module.exports = {
getTrainStations
};
Then. in app.js file, I call it as:
const stations = (async () => {
let res = await stationsModule.getTrainStations();
return res;
})();
If I debug "res" it is clearly a node-cache object, I can call the get method with a key and get its value. However, when it gets assigned to stations, it does it in the form of a resolved promise, and when I debug I can see the values, but I can't figure out how to return the value of the promise and use it as I want.
So basically the question is, why "res" got a proper node-cache object, but later on when I want to use "stations" I have a resolved promise instead. And also, how do I access to the values within the resolved promise? I tried with .then() and I can print the values in a console.log but can't use them at all.
Thanks in advance for the help!
async function calls always return a promise for the result of an [asynchronous] operation. In
const stations = (async () => {
let res = await stationsModule.getTrainStations();
return res;
})();
stations is assigned the promise returned by the anonymous arrow function call const stations = (async () => {...})();
The promise will be resolved with res when the data becomes available.
It may be worth noting you can't return an asynchronous result (obtained in the future) to the same call out from the event loop that requested the operation. In that turn of the event loop the result is pending.
Once await has been used, all code using the result must be in an async function, accessed using promise handlers in ordinary code, or triggered by a timer or event fired after the data arrives.

Knex.js non-terminating functions

I don't have any problem in this question, I am just interested in how knex.js menaged to something.
In code, you can write something like this
let search = knex.table('users').select('something')
if(params.minprice) search.where('minprice', params.minprice)
if(something) search.something()
let result = await search
It works, but I don't get how did they menage to hold query execution until await occured? If we did await, it means function was async aka returned a promise. But in javascript, promise executes as soon as function that returned it is called, it does not care is there .then() or .catch(). Should not query execution start al line 1? What is more, when I log search, it is not a promise, but some kind of object, so how can it be awaited?
Can someone provide a simple example how to achieve such a behaviour?
I'm guessing that search contains a property named then, which is a function that initiates the search and also behaves similarly to the functionality of Promise.prototype.then.
E.g.:
// define Searchable
let Searchable = function() {
this.searchParam = 'param';
};
Searchable.prototype = {
setSearchParam: function(p) { this.searchParam = p; },
initiateSearch: async function() {
// lots of fancy searching
console.log(`Searching with param "${this.searchParam}"`);
return `search based on "${this.searchParam}"`;
},
then: async function(callback) {
// initiate the search:
let searchResults = await this.initiateSearch();
// behave kind of like `Promise.prototype.then`!
return callback(searchResults);
}
};
// now work with it:
(async () => {
let searchable = new Searchable();
searchable.setSearchParam('mySearchParam');
console.log('No search performed yet!');
// Here's the fancy usage you're concerned with (it invokes `searchable.then`):
let searchResult = await searchable;
console.log('RESULT:', searchResult);
})();
Calling await on some value will attempt to call value.then as if it were a function accepting a callback argument.
Knex query builder is mutable and thenable object.
So every time you call for example search.where(...) for that query builder, its internal state changes and stores that new where clause.
Query builder being thenable means that the object has .then() method and when you call await search it is actually pretty much equivalent with await Promise.resolve(search) which first executes thenable and converts it to promise which is then resolved or an exception might occur.
Thenable objects are actually pretty important part of promise spec providing interoperability API between promises and non-promise objects.

when trying push a data to my array into a promise this don't save the data

i have this code:
let splatshArtData = [];
splatshArt.getSplatchArt(participants[i].championId).then((splatshArtUrl) => {
splatshArtData.push(splatshArtUrl);
});
console.log(splatshArtData);
I want add the "splatshArtUrl" to my array, but this don't work, when i try print the data this don't print nothing, i don't know how to do that, any idea?
The problem that you're facing here is that getSplatchArt returns a promise, and promises take time to resolve. You can therefore never guarantee that splatshArtData.push(splatshArtUrl); will run before the console.log.
The solution is to move all logic which requires data returned from the promise to within the promise callback. This can of course include calls to other functions.
// function to process the splashArtData - will be called from the promise
// when the promise is resolved.
function processSplashArt(data) {
// this will now print as you are expecting
console.log(data);
}
let splatshArtData = [];
splatshArt.getSplatchArt(participants[i].championId).then((splatshArtUrl) => {
splatshArtData.push(splatshArtUrl);
// pass the splashArtData to the callback function - it's now ready
processSplashArt(slashArtData);
});
JavaScript is synchronous, thus each line of code will be executed right after one another.
If we annotate your code with line numbers like below
1. let splatshArtData = [];
2. splatshArt.getSplatchArt(participants[i].championId).then((splatshArtUrl) => {
3. splatshArtData.push(splatshArtUrl);
});
4. console.log(splatshArtData);
you are assuming that it will run in the order of 1, 2, 3, 4, while in reality it will run in the order of 1, 2, 4, 3. Why is that? Because JavaScript is synchronous, and the function at line 2 is asynchronous, meaning that you'll have to await that before you can continue. If you don't the splatshArtData variable will be an empty array since the data hasn't been fetched yet.
If you want to return the fetched data and use it in another function, you shouldn't mix it will callbacks as suggested in another answer, but instead chain the promise and use the resolved value from the function that fetches the data.
function getSplatshArt() {
let splatshArtData = [];
//Return a promise
return splatshArt.getSplatchArt(participants[i].championId).then((splatshArtUrl) => {
console.log(splatshArtData); //this will log out the data
splatshArtData.push(splatshArtUrl);
return splatshArtData; //this will be the resolved value from the promise
});
}
//Call the function and access the resolved data in the .then() block
getSplatshArt()
.then(data => {
console.log(data); //this is the data returned from the getSplatshArt function
});
Looking at your code, I get the impression that you're looping over an array of ID's, and if you want to fetch multiple values at once, this wont work since you have to handle multiple promises. But that is another question and I think you should do some more research of your own before asking about that.
Try this:
let splatshArtData = [];
splatshArt.getSplatchArt(participants[i].championId).then((splatshArtUrl) => {
splatshArtData.push(splatshArtUrl);
console.log(splatshArtData);
});
The function inside the then runs right after the asynchronous function getSplatchArt resolves it's promise, so it was running the console.log before the item is added to the array.

Categories