Wait for a response from a function - discord.js

I tried making a command in my discord.js bot, however the embed with the info gets sent BEFORE all the variables were set (this is beacuse I use Firestore, it takes a second to get the data)
The function would look something like this:
function getData(){
var level = 0
let levels = database.collection('guilds').doc(message.guild.id).collection('levels').doc(person.id)
levels.get().then((q) => {
if(q.exists){
let data = q.data()
level = data.level
return level
}
})
}
message.channel.send(getData())
// would send 0 because the function didnt get the data in time
How can I call a function and then wait for a response?
I tried messing around with async and await but I dont really know how to use them, which kept throwing errors.

Related

How to update my redux store synchronously?

I have a function that is being dispatched twice in small time duration. Suppose 1st call was made on time X and second call was made on time Y. Where Y > X and difference between X and Y is 5 millisecond or less.
Call made at time Y is updating the store 1st and then call made at time X. So my store is being updated with outdated data. How to overcome this situation ?
I am using redux-thunk.
I'm assuming your problem is that the result for the first async call arrives after the result for the second async call (which has priority) has already arrived.
The general idea to deal with this is that you need to be able to keep track of the latest/most recent call, versus the other, outdated calls that should be ignored and not affect the state anymore.
To solve this, save the value of Date.now() in your state to remember when the most recent request started. In thunks you have access to getState, so you can check if the current request is still the one that has most recently started.
Pseudo code:
const myThunk = () => async (dispatch, getState) => {
const startedAt = Date.now();
// this needs to write state.mostRecentRequestStartedAt = action.payload.startedAt; in the reducer
dispatch(requestStarted(startedAt));
const result = await doSomethingAsync();
// At this point, other more recent requests might have started!
const { mostRecentRequestStartedAt } = getState();
if (startedAt === mostRecentRequestStartedAt) {
dispatch(saveResult(result));
} else {
// result is from an outdated request. Ignore it or do something else here.
}
};

JSON stored into an array not callable by specific index

I am trying to develop an app for my fantasy baseball league to use for our draft (we some kind of quirky stuff all the major sites don't account for) - I want to pull some player data to use for the app by using MLB's API. I have been able to get the response from MLB, but can't do anything with the data after I get it back. I am trying to store the JSON into an array, and if I console.log the array as a whole, it will give me the entire chunk of data, but if I try to call the specific index value of the 1st item, it comes back as undefined.
let lastName = 'judge';
let getData = new XMLHttpRequest;
let jsonData = [];
function getPlayer () {
getData.open('GET', `http://lookup-service-
prod.mlb.com/json/named.search_player_all.bam?
sport_code='mlb'&active_sw='Y'&name_part='${lastName}%25'`, true)
getData.onload = function() {
if (this.status === 200) {
jsonData.push(JSON.parse(this.responseText));
}
}
getData.send();
console.log(jsonData);
}
When I change the above console.log to console.log(jsonData[0]) it comes back as undefined. If I go to the console and copy the property path, it displays as [""0""] - Either there has to be a better way to use the JSON data or storing it into an array is doing something abnormal that I haven't encountered before.
Thanks!
The jsonData array will be empty after calling getPlayer function because XHR loads data asynchronously.
You need to access the data in onload handler like this (also changed URL to HTTPS to avoid protocol mismatch errors in console):
let lastName = 'judge';
let getData = new XMLHttpRequest;
let jsonData = [];
function getPlayer () {
getData.open('GET', `https://lookup-service-
prod.mlb.com/json/named.search_player_all.bam?
sport_code='mlb'&active_sw='Y'&name_part='${lastName}%25'`, true)
getData.onload = function() {
if (this.status === 200) {
jsonData.push(JSON.parse(this.responseText));
// Now that we have the data...
console.log(jsonData[0]);
}
}
getData.send();
}
First answer from How to force a program to wait until an HTTP request is finished in JavaScript? question:
There is a 3rd parameter to XmlHttpRequest's open(), which aims to
indicate that you want the request to by asynchronous (and so handle
the response through an onreadystatechange handler).
So if you want it to be synchronous (i.e. wait for the answer), just
specify false for this 3rd argument.
So, you need to change last parameter in open function as below:
getData.open('GET', `http://lookup-service-
prod.mlb.com/json/named.search_player_all.bam?
sport_code='mlb'&active_sw='Y'&name_part='${lastName}%25'`, false)
But from other side, you should allow this method to act asynchronously and print response directly in onload function.

Akka.net - Streams with parallelism, backpressure and ActorRef

Tying to learn how use Akka.net Streams to process items in parallel from a Source.Queue, with the processing done in an Actor.
I've been able to get it to work with calling a function with Sink.ForEachParallel, and it works as expected.
Is it possible to process items in parallel with Sink.ActorRefWithAck (as I would prefer it utilize back-pressure)?
About to press Post, when tried to combine previous attempts and viola!
Previous attempts with ForEachParallel failed when I tried to create the actor within, but couldn't do so in an async function. If I use an single actor previous declared, then the Tell would work, but I couldn't get the parallelism I desired.
I got it to work with a router with roundrobin configuration.
var props = new RoundRobinPool(5).Props(Props.Create<MyActor>());
var actor = Context.ActorOf(props);
flow = Source.Queue<Element>(2000,OverflowStrategy.Backpressure)
.Select(x => {
return new Wrapper() { Element = x, Request = ++cnt };
})
.To(Sink.ForEachParallel<Wrapper>(5, (s) => { actor.Tell(s); }))
.Run(materializer);
The Request ++cnt is for console output to verify the requests are being processed as desired.
MyActor has a long delay on every 10th request to verify the backpressure was working.

Setting a variable out of a confusing method in Angular JS

So I have a variable called stuff, which is declared as stuff:any and I would like to populate it with the data that I get from:
this.http.post("WORKING_IP_ADDRESS", JSON.stringify(
{"thing1": this.thing1,
"thing2": this.thing2,
}), {headers: headers}).map(
res => res.json()).subscribe(
data => {
(JSON.stringify(data));
})
When I run an alert() method on the last JSON.stringify(data));, I get the data that I want, but when I try to set it equal to the stuff variable by doing this.stuff = JSON.stringify(data));, it doesn't work. I'm new to Angular, so I know I'm probably doing something wrong. Anyone know what I need to do to get the final JSON.stringify(data) into my stuff variable?
The reason is that http.post is a observable. That means that its gonna resolve later. It's gonna resolve later because its gonna take some time to connect to that working ip address, get the data and do something with it.
Imagine a scenario like this
let stuff = 'no';
// Equal to http.post
const resolvesLater = setTimeout(function() {
stuff = 'yes';
console.log(stuff);
},2000);
console.log(stuff);
https://jsfiddle.net/7c6kfurp/ Open up the console and press play. See what happens.
You would think that the console would look like
yes
yes
But it actually is gonna be
no
yes
Because what happens in the setTimeout happens later. So the order of the lines don't tell you in what order the code executes.
Its gonna set stuff = 'no' at the beginning.
Then its gonna go into the setTimeout/http.post function
That's gonna take some time.
Meanwhile the browser continues
It logs out stuff (still no)
Then the setTimeout/http.post resolves
Its gonna set stuff = yes
Then log out stuff (which is now yes)
In angular 2 you subscribe to observables (like you do) but it would probably be better to decouple the fetch and subscribe. So create a service with a function:
fetchStuff(): Observable<Stuff[]> {
return his.http.post("WORKING_IP_ADDRESS", JSON.stringify({
"thing1": this.thing1,
"thing2": this.thing2,
}), {headers: headers}).map(res => res.json());
}
And then you subscribe to it and assign the stuff variable for the views
getStuff() {
this.MyService.fetchStuff()
.subscribe(stuff => this.stuff= stuff);
}
And finally in your view
<ul class="items">
<li *ngFor="let item of stuff>
<span>{{item.property}}</span>
</li>
</ul>
Observables means that when the object changes all other objects that are dependant on it are notified.
So you make a request to your working-ip, first nothing happens, like I explained above. We're waiting for the server to respond, so something with the data you sent and then send you something back.
In order to know when something happened, you subscribe to it. Just like you would subscribe a newspaper to get the latest news. When something happens you get notified. You want to know when you get response from the-working-ip.
The reason I broke it up was to seperate the fetching and the subscription, just to seperate the concerns. You don't have to and I've probably confused things more for you. Sorry about.
Simply try this:
this.http.post("WORKING_IP_ADDRESS", {
"thing1": this.thing1,
"thing2": this.thing2
}, {headers: headers})
.map(res => res.json())
.subscribe(data => this.stuff = data);
Here's a link on how to create services
https://angular.io/docs/ts/latest/guide/server-communication.html

Nodejs not sending response to Angular?

I have a doozy that I can't figure out whats going on.
In Mongo, I do a document.find(), which returns an array of object/s - All good.
I'm then trying to send on two objects back to the Angular Controller, the document object/s and the length of the array of objects.
Code:
function loadConnections(req, res) {
getConnections(req.user)
.then(function(results){
console.log('here');
console.log(results);
console.log(results.length);
var returnObject = {}
returnObject.count = results.length;
//returnObject.results = results[0]; // PROBLEM LINE
res.status(200).send(returnObject);
});
}
Problem I'm facing. In this scenario, it returns an array with 1 object. The array looks like:
[{id: XXX, test: YYY, test1: ZZZ}]
These have been what I've tried and tested:
returnObject.results = results[0].id; // works
returnObject.results = results[0].test; // works
returnObject.results = results[0].test1; //works
returnObject.results = results[0]; // doesn't work
returnObject.results = results; //doesn't work
But if I try to pass the entire object or the entire array, it hits an issue and doesn't send the response to the controller.
Any thoughts?
If you are using express, try to do a
res.send(200, returnObject);
or
res.json(200, returnObject);
that should do the trick!
Personally I would just calculate the length of the array after it arrives in my Angular client, rather than on the server. However, you should be able to accomplish what you're trying to do by doing this:
var returnObject = {
'count': results.length,
'results': results
};
res.json(returnObject);
Here's the doc: http://expressjs.com/en/api.html#res.json
Also just for general troubleshooting, the first thing you want to do is figure out where the inconsistency is starting. Does the data look right on the server before you send the response? Does the data look right on the client when your API handler receives the response? (I'm assuming $resource, or maybe you're using $http). So add a line like this just before you send the response from the server, and then add a similar line just after you receive the response in the client:
console.log(JSON.stringify(returnObject, null, 2));
Turns out it was my lodash library. I was using _.pluck and somewhere along the way, it's stopped working. Had to update it to _.map.

Resources