Why is some of my code running before other ones? - javascript

So i was running my script and i was wondering why some of my code was running before eachother.
For example, i had a function, and i called it last, AFTER a message was supposed to be displayed. But instead it ran the function first THEN displayed the message.
Also, i was noticing with displaying messages, it would display in a random order each time. (Wierd Huh.)
I managed to fix some of this by creating a bunch of .this's, but i don't want to do that so much in the future as it makes code very confusing.
Here is a snippet of some of my code that this is happening to:
else if (input.startsWith('CALL')) {
//First
bot.sendMessage(message, ':arrow_right: Private Messaging You To Decrease Spam :arrow_left:');
//Second
bot.sendMessage(user.id, ':rotating_light: This feature is experimental. You may experience bugs/glitches when using it. :rotating_light: \n').then(() => getUser()); // << Third
var senderId = message.sender.id; // << Fourth
function getUser() {
try {
var userList = []
for (var user of bot.users) {
if (user.status == "online" && user.bot == false) {
userList.push(user)
}
}
bot.sendMessage(senderId, ':telephone: :arrow_right: Users Found That Meet Search Criteria: ' + userList.length + ' out of ' + bot.users.length + '.'); //Fifth
bot.sendMessage(message, ':telephone: :arrow_right: User Found: ' + userList[Math.floor(Math.random() * userList.length)]); //Sixth
} catch (err) {
bot.sendMessage(message, err)
}
console.log(userList);
console.log(userList.length);
}
}
The code works, it's just the order i was worried about.
Thanks in advance for the help :)
EDIT: I added comments to say what the order should be.
EDIT #2: Clarified Question: I was wondering how i would be able to make the code run in a certain order. And wait for a code prior to run first.

I assume bot.sendMessage makes a network request of some sort to some other system, and the issue you're observing is that those network requests seem to take effect in an unpredictable order. This makes sense, because you're not waiting for one request to finish before starting the next one.
Imagine you opened a web browser and opened two tabs to two different URLs at the same time. Which page would load first? That's basically what your code is doing.
Because I see a .then in one place, I'm going to further assume that bot.sendMessage returns a promise. So go ahead and use the promise to wait for the first request to finish before starting the next one.
Specifically, change this:
bot.sendMessage(senderId, ':telephone: :arrow_right: Users Found That Meet Search Criteria: ' + userList.length + ' out of ' + bot.users.length + '.');
bot.sendMessage(message, ':telephone: :arrow_right: User Found: ' + userList[Math.floor(Math.random() * userList.length)]);
to this:
bot.sendMessage(senderId, ':telephone: :arrow_right: Users Found That Meet Search Criteria: ' + userList.length + ' out of ' + bot.users.length + '.').then(() => {
bot.sendMessage(message, ':telephone: :arrow_right: User Found: ' + userList[Math.floor(Math.random() * userList.length)]);
});
(Ditto with your other messages that you want to happen in a certain order.)

the function you use to send the message runs asynchronously, so you must wait for the end of the first call before invoke the next one (and the rest of the code). smarx gave you a good example about what to do.

Related

Is there a better way of sending messages to specific channels in specific servers?

I'm trying to make a logs script, however, I can not get it to work. Is there a better way?
I've tried switching around the properties, but it doesn't seem to work.
client.on('message', message => {
var sender = message.member.user.tag
var channel = message.channel.name
var message = message.content
var server = message.guild
let embed = new Discord.RichEmbed()
.addField('**' + sender + '** said ' + message + ' in ' + channel + ', ' + server)
.setColor('#4286f4')
// This is the line I'm having problems with:
client.guilds.get('575957043211403265').channels.get('575957043211403267').sendEmbed(embed);
});
If the IDs you're using are correct, then your code should be valid, as long as you're using the library from the stable branch.
You're using the TextChannel.sendEmbed() method, which is deprecated: that means that it'll be removed in the future versions. If you installed the master branch that method won't be available (check the docs here).
There is another way of sending embeds:
TextChannel.send({ embed: yourEmbed });
In your case, it would be:
client.guilds.get('575957043211403265').channels.get('575957043211403267').send({ embed });
If that doesn't work, please include the error in your reply, you might have missed something in the question :)

NodeJs / Google Firebase functions string methods not working

I have a Google Assistant app that uses some API's to retrieve and deliver bus arrival times for my local university. The thing is the API returns the arrival times in a string like this:
"2018-51-02T06:51:11"
I try to maniuplate that string with the slice and indexOf functions that exist within javascript to just get the final time portion of the string, the exact code is
finalString = departure.slice(departure.indexOf('T')+1, departure.length);
but at the end of it all it still only prints out and responds with the original string. Offline and local on my machine that code works, but when uploaded to Firebase Functions it no longer works. Any help with this issue?
app.intent("wheres the catabus", (conv, {route}) => {
var routeDetails;
var closest_stop;
var finalString;
return cataAPIService.getRouteDetails(route)
.then((routeData) => {
routeDetails = routeData;
closest_stop = cataAPIService.findClosestStop(routeData, conv.device.location);
return cataAPIService.getStopDetails(closest_stop.StopId)
})
.then((stopData) => {
var departure = cataAPIService.getEstimatedStopDeparture(routeDetails, stopData);
finalString = departure.slice(departure.indexOf('T')+1, departure.length);
conv.ask('The closest stop to you is at ' + closest_stop.Name + '. The next departure is scheduled for ' + finalString);
})
.catch((error) => {
console.log(error);
conv.ask("I can't get that information right now, please try again.");
});
});
I wasn't able to duplicate your problem on Firebase Cloud Functions using node.js 6 and the following code:
var departure="2018-51-02T06:51:11";
var finalString = departure.slice(departure.indexOf('T')+1, departure.length);
console.log('finalstring',finalString);
As expected, it sent the following to the logs:
finalstring 06:51:11
If you show the complete code that is causing the problem, we may be able to help you out.
The behavior you're seeing suggests that the "T" isn't actually in the string.
Otherwise, I typically use code more like this:
var f2 = departure.split('T')[1];
(but only if I know there is actually a T in the datetime)

Weird (caching) issue with Express/Node

I've built an angular/express/node app that runs in google cloud which currently uses a JSON file that serves as a data source for my application. For some reason, (and this only happens in the cloud) when saving data through an ajax call and writing it to the json file, everything seems to work fine. However, when refreshing the page, the server (sometimes!) sends me the version before the edit. I can't tell whether this is an Express-related, Node-related or even Angular-related problem, but what I know for sure is that I'm checking the JSON that comes in the response from the server, and it really is sometimes the modified version, sometimes not, so it most probably isn't angular cache-related.
The GET:
router.get('/concerts', function (request, response) {
delete require.cache[require.resolve('../database/data.json')];
var db = require('../database/data.json');
response.send(db.concerts);
});
The POST:
router.post('/concerts/save', function (request, response) {
delete require.cache[require.resolve('../database/data.json')];
var db = require('../database/data.json');
var concert = request.body;
console.log('Received concert id ' + concert.id + ' for saving.');
if (concert.id != 0) {
var indexOfItemToSave = db.concerts.map(function (e) {
return e.id;
}).indexOf(concert.id);
if (indexOfItemToSave == -1) {
console.log('Couldn\'t find concert with id ' + concert.id + 'in database!');
response.sendStatus(404);
return;
}
db.concerts[indexOfItemToSave] = concert;
}
else if (concert.id == 0) {
concert.id = db.concerts[db.concerts.length - 1].id + 1;
console.log('Concert id was 0, adding it with id ' + concert.id + '.');
db.concerts.push(concert);
}
console.log("Added stuff to temporary db");
var error = commit(db);
if (error)
response.send(error);
else
response.status(200).send(concert.id + '');
});
This probably doesn't say much, so if someone is interested in helping, you can see the issue live here. If you click on modify for the first concert and change the programme to something like asd and then save, everything looks fine. But if you try to refresh the page a few times (usually even up to 6-7 tries are needed) the old, unchanged programme is shown. Any clue or advice greatly appreciated, thanks.
To solve: Do not use local files to store data in cloud! This is what databases are for!
What was actually the problem?
The problem was caused by the fact that the App Engine had 2 VM instances running for my application. This caused the POST request to be sent to one instance, it did its job, saved the data by modifying its local JSON file, and returned a 200. However, after a few refreshes, the load balancing causes the GET to arrive at the other machine, which has its individual source code, including the initial, unmodified JSON. I am now using a MongoDB instance, and everything seems to be solved. Hopefully this discourages people who attempt to do the same thing I did.

Prevent JQuery .HTML overwriting previous .HTML before its displayed

I am currently using a multi-dimensional array to store values and then loop round it based on if it meets two requirements does a number match and does it have a set state E.G 487 Online.
This changes in real time based on what event happens to be caught and inserted in the MD array on the server idea and everything is grand on that side of things.
Am trying to visual represent each state of a call in the following format:
If phone device is online turn tile red otherwise turn green and do .HTML.
If phone is ringing turn tile yellow and do .HTML.
If phone is in a call then turn the tile orange and do .HTML.
If phone just hangup then and do .HTML (but it doesn't do this) then turn blue via a css class using .addClass......then remove it after 3 seconds. (It wont display otherwise because status online gets caught right after so you dont even see it turn blue hence using a setTimeout to stop this.)
Steps 1 to 3 work accordingly the issue comes in with step 4.
The issue am having with this is am using JQuery .HTML to overwrite content in the tile every time the phone changes state but after some debugging and fiddling around I have found that the issue seems to be JQuery .HTML and/or how am using it and the setTimeOut I think but I don't know why.
Problem is the Hangup event gets caught........ .HTML here doesn't seem to display and seems to get overwritten by the .HTML in the online event which gets caught straight after hangup and therefore displays .html from the online event instead.
I found when I remove the .HTML at step 1 it stops the issue, but I need it in step 1. But if I leave it there it seems to be overwriting the .HTML in step 4 which I also need for some reason.
Array looks like this with the extension number, SIP device status, current state the device is in e.g Ringing:
[ '487', 'online', 'Hangup' ],
[ '488', 'online' ],
[ '477', 'online', 'Hangup' ] ]
What the server side events generally look like at the point where the event is caught:
477 and 487 both hungup
[ [ '487', 'online', 'Hangup' ], [ '477', 'online', 'Hangup' ] ]
something happened to a ChannelDestroyed
Channel Output ChannelDestroyed
something happened to an endpoint
EndpointStateChange
477 current state is: online
[ [ '487', 'online', 'Hangup' ], [ '477', 'online', 'Hangup' ] ]
Here is my code at the moment:
//Handles events to signal current call states aka if 488 dials 487 highlight both tiles with those values.
socket.on("eventsCalls", function (calldata) {
for (var i = 0; i < calldata.length; i++) {
if (calldata[i][0] && calldata[i][2] === "Ringing") {
$("div[class*='tile']:contains('" + calldata[i][0] + "')").css("background-color", "yellow").append("<h4>User</h4><p>" + calldata[i][0] + " Is Ringing</p>");
} else if (calldata[i][0] && calldata[i][2] === "Hangup") {
$("div[class*='tile']:contains('" + calldata[i][0] + "')").html("<h4>User</h4><p>" + calldata[i][0] + " just hungup</p>").addClass("hangup");
setTimeout(function () {
$("div[class*='tile']").removeClass("hangup");
}, 3000);
} else if (calldata[i][0] && calldata[i][2] === "ANSWER") {
$("div[class*='tile']:contains('" + calldata[i][0] + "')").css("background-color", "orange").html("<h4>User</h4><p>" + calldata[i][0] + " Is Busy</p>");
}
}
});
// Handles which sip devices are currently registered and displays them on the web page.
socket.on("eventsRegister", function (regisdata) {
for (var i = 0; i < regisdata.length; i++) {
if (regisdata[i][0] && regisdata[i][1] === "online") {
$("div[class*='tile']:contains('" + regisdata[i][0] + "')").css("background-color", "green").html("<h4>User</h4><p>" + regisdata[i][0] + " Online</p>");
} else if (regisdata[i][0] && regisdata[i][1] === "offline") {
$("div[class*='tile']:contains('" + regisdata[i][0] + "')").css("background-color", "red").html("<h4>User</h4><p>" + regisdata[i][0] + " Offline</p>");
}
}
});
Is there any better alternatives or workarounds for this issue am having?
EDIT: JSFiddle for an idea of what am trying to do its hard to replicate the catching of events but when it hits hangup the .html seems to be overwritten by Online event which seems to happen at the same time I think. It doesn't work like that for the last two events on my code the colors change but the .HTML for hangup seems to be overwritten by online.
I can't say for certain, but your setTimeout is missing a delay parameter.
var hangupDelay = 5000; // 5 seconds.
setTimeout(function () {
$("div[class*='tile']").removeClass("hangup");
}, hangupDelay );
This should remove the hangup class after 5 seconds anyway.
If you do not specify the setTimeout delay param; you get it almost instantly:
https://developer.mozilla.org/en/window.setTimeout#Minimum_delay_and_timeout_nesting
delay is the number of milliseconds (thousandths of a second) that the
function call should be delayed by. If omitted, it defaults to 0. The
actual delay may be longer; see Notes below.
This might result in the hangup class instantly being removed and appearing to not be working.

Are you able to update a webkitNotifications?

Had a look around an can only really find resources on creating notifications, and not updating them. Heard it might be possible if I used chrome.notifications instead but again can't find anyway to do it.
This currently is my code, and it ends up just closing any previous notification then reissuing it.
if (window.webkitNotifications){
if(window.webkitNotifications.checkPermission() > 0){
}
else if (seconds == 0)
{
var thumb = 'images/icon.png';
var title = 'Current Task';
var body = "Active " + hours + " hours and " + minutes + " minutes";
if (popup != "") {
popup.cancel();
}
popup = window.webkitNotifications.createNotification(thumb, title, body);
popup.show();
}
}
Anyone know if it's possible to update a notification instead of just recreate it? Would make it much more user friendly, and for a live feed of information more of a float over any other job they might be doing?
Once the notification has been created, the way to communicate with it is through message passing. Read up on it here: http://developer.chrome.com/extensions/messaging.html
Timeline:
Background process creates notification with content. Notifiation is created and starts listening for messages, all well and good.
Background process finds new information and checks whether the notification is still alive (via a variable in localStorage or usage of the Tabs API, or however you want to do this).
If notification was found to be alive, background process passes a message about new information, which the notification picks up and displays.

Categories

Resources