Callback and/or Promises javascript - javascript

It's been 2 days since I'm trying to understand my error. So far what I've learnt is that i will never be able to bypass "undefined" returned value because i cannot understand callback or promises... I rode all the poste , did some easy exemple , but I 'm not undertanding how to make it happen on my code ...
function realloot(data){
return data;
console.log(`${data}`);
}
function lootbox_openning(callback, user, type, nombre){
let sqlQueryopenbox = `SELECT item_qty FROM users_items WHERE discord_id = '${user}' AND item_id = ${type};`
let token_won=0;
let real_token_won=0;
let common_pp_looted = 0;
let rare_pp_looted = 0;
let epic_pp_looted = 0;
db.query(sqlQueryopenbox, (err, rows) => {
let user_box_real_qty = rows[0].item_qty;
let sql;
if (err) {
real_token_won="sql error";
throw err;
}
if (nombre > user_box_real_qty){real_token_won="error number";}
else {
//function open
if (type==1) {
for (var i = 0; i <= nombre; i++){
token_won=little_box_open();
real_token_won=real_token_won+token_won;
}
var myreturn = callback(real_token_won);
console.log(`${myreturn}`);
return myreturn;
}
if (type==2) {}
if (type==3) {}
}
});
}
//this is a bot discord so huge on.message here...
case "open":
if (!args[1]) return message.channel.send('please give value box | bigbox');
if (args[1] ==='box' ){
if (!args[2]) {message.channel.send ("Specify number please");}
if (args[2]) {
var number = parseInt(args[2]);
if (Number.isInteger(number)){
message.channel.send ("You re openning "+args[2]+" boxes");
**var token_won = lootbox_openning(realloot, message.author.id, 1, args[2]);** //PROBLEM IS HERE
if (token_won==="error number"){message.channel.send ("Vous n'avez pas assez de box !");}
else {message.channel.send ("you won : "+token_won+" tokens !");}
}
else message.channel.send ("Give a valid number");
}
}
Please be gentle, I already hit my head so hard on others posts but it seems like I need more explanations...

async logic is a common place for newcommers to get tripped up on. But, it basically boils down to doing this:
Example of a synchronous code:
(this is assuming that db.query() was written as a sync function, which its not)
function doQuery(id) {
let res = db.query(`SELECT * FROM table WHERE id=${id}`)
return res
}
Example of asynchronous code (which using db.query() as an async function)
function doQuery(id, callback) {
db.query(`SELECT * FROM table WHERE id=${id}`, function(res) {
callback(res)
})
}
The main difference here is that instead of doing return res you have to do callback(res). This will always be the case when working with async code.
And its important to note that once you're in the async world, you can never go back to a sync world. i.e. This is impossible:
// some sync logic
let resultOfAsyncOperation = someAsyncFunction()
// some sync logic
Once you're dealing with callbacks, you have to use callbacks everywhere. This is because the user of an async function has to itself be async. The only exception is if you don't care about what's getting returned or when, you just want it to go off and do some task.
So, this is how these principles applies to your specific chunk of code. This snippet of code is exactly the issue I was describing - you're trying to use an async function inside of sync logic.
var number = parseInt(args[2]);
if (Number.isInteger(number)) {
message.channel.send("You re openning " + args[2] + " boxes"); **
var token_won = lootbox_openning(realloot, message.author.id, 1, args[2]); ** //PROBLEM IS HERE
if (token_won === "error number") {
message.channel.send("Vous n'avez pas assez de box !");
} else {
message.channel.send("you won : " + token_won + " tokens !");
}
} else message.channel.send("Give a valid number");
You'll have to convert this chunk of code to also be async, like this:
message.channel.send("You re openning " + args[2] + " boxes");
function callback(token_won) {
realloot(token_won)
if (token_won === "error number") {
message.channel.send("Vous n'avez pas assez de box !");
} else {
message.channel.send("you won : " + token_won + " tokens !");
}
}
lootbox_openning(callback, message.author.id, 1, args[2]);
(it's possible I didn't fully understand how you intended your original code to work, so take this example with a grain of salt. It shows the principle, but you'll have to tweak it to work for your needs)

Related

Firebase - remote config on web sometimes gets values and sometimes not

I'm new to programming in Javascript (I haven't even been programming for a month, but I have experience in other non-asynchronous languages).
I'm having trouble connecting the Firebase config to my website, sometimes it shows values, other times it doesn't.
if (app_data) {
console.log("Step 0");
remoteConfig = getRemoteConfig(app_data);
remoteConfig.settings.minimumFetchIntervalMillis = 10000;
} else {
console.log("No se ha podido conectar a la base de datos.");
}
if (fetchAndActivate(remoteConfig)) {
console.log("Paso por 2");
obj_config = getAll(remoteConfig);
console.log("Paso por 3");
Object.entries(obj_config).forEach((x) => {
const [key, entry] = x;
if (key === "contract_address") {
contract_token = entry["_value"];
console.log("Key Address: ", entry["_value"]);
}
console.log("Key: ", key);
console.log("Source: ", entry.getSource());
console.log("Value: ", JSON.stringify(entry["_value"]));
});
}
If someone could help me, I would be very grateful.
Greetings
fetchAndActivate is async, so it won't have finished fetching yet:
instead of
if (fetchAndActivate(remoteConfig)) {
//code
}
try
fetchAndActivate(remoteConfig).then(() => {
// code
});
If you are using Javascript, you could try to use await in your code because the fetching step is asynchronous.
Something like
const rcResult = await asyncFetchFromRC()

I want to read a certain amount of lines from a text file, and with them to create an object after reading the lines using JavaScript

okay, so this is my requirement: The application must read each line from the text file. A class can be used so that after reading a certain number of lines an object is created (in this way the application is more clearly structured). After reading a data set that corresponds to a student's data, it will add this data set to a string (separate so that it is presented in consecutive rows).
So i have these information of 2 students which are one under the other like in the picture below but without the name address etc.(it doesn't show quite right in here).
Ebonie Rangel
7175 Yukon Street
(507) 833-3567
Geography
Keenan Ellwood
2 Elm Lane
(894) 831-6482
History
which are in that file. and after reading every line, I am supposed to add Name in front of the first line, Address in front of the second.. phone and Course and so on.
The result should look like this:
This is what i have for now (I have to use Fetch to get to the file, async and await. or with Promise)
let button = document.getElementById("text-button");
let textArea = document.getElementById("text-area");
button.addEventListener("click", function () {
getData();
});
//cod fetch
async function getData() {
try {
let response = await fetch('fileName.txt');
if (response.status !== 200) {
throw new Error("Error while reading file");
}
let text = await response.text();
textArea.innerHtml = text;
} catch (err) {
textArea.innerHTML = 'Problem occurred: ' + err.message;
}
}
please help! I am stuck since forever on this.
Since you're pulling from a .txt file I think its important to understand the line breaks being used in the file. Here's a decent link I found that says all you need at the top of the article: End of Line or Newline Characters
I opened up the .txt file in Notepad++ like the article recommended and saw this:
The [CR][LF] being displayed after each line means that the newline characters used are \r\n.
When you understand that you realize you can use those line breaks to separate your string at each line break.
Here's the MDN for String.split() String.prototype.split()
String.split('\r\n') will return an Array of items, specifically the strings that were between but not including the \r\n characters.
Let's add this to the getData function:
let button = document.getElementById("text-button");
let textArea = document.getElementById("text-area");
button.addEventListener("click", function () {
getData();
});
//cod fetch
async function getData() {
try {
let response = await fetch('fileName.txt');
if (response.status !== 200) {
throw new Error("Error while reading file");
}
let text = await response.text();
//New stuff:
let arrayOfText = text.split('\r\n');
//Now we could add what we want before the text.
//We need to do every 4 lines so lets use this as a chance to learn % better
arrayOfText = arrayOfText.map((textItem, index) => {
let remainder = (index) % 4 //This will return 0, 1, 2, 3
//switch but you could use anything
switch (remainder) {
case 0:
textItem = 'Name: ' + textItem + '\r\n';
break;
case 1:
textItem = 'Address: ' + textItem + '\r\n';
break;
case 2:
textItem = 'Phone: ' + textItem + '\r\n';
break;
case 3:
textItem = 'Course: ' + textItem + '\r\n\r\n'; //two here to separate the groups
break;
//we need a default so lets make it just return textItem if something goes wrong
default:
break;
};
//Our new array has all the info so we can use
//Array.prototype.join('') with an empty string to make it a string.
//We need those old line breaks though so lets put them
//in the switch returns above.
text = arrayOfText.join('');
//End of my changes/////////////
textArea.innerHtml = text;
} catch (err) {
textArea.innerHTML = 'Problem occurred: ' + err.message;
}
}
I hope this works out for you. Its not the most glamorous solution but its a good learning solution because it uses only things you learn early on in your studies.
Let me know if I can clarify anything!
async function getData() {
try {
let response = await fetch('https://v-dresevic.github.io/Advanced-JavaScript-Programming/data/students.txt');
if (response.status !== 200) {
throw new Error("Error while reading file");
}
let text = await response.text();
const lines = text.split('\n');
const CHUNK_SIZE = 4;
textArea.innerHTML = new Array(Math.ceil(lines.length / CHUNK_SIZE))
.fill()
.map(_ => lines.splice(0, CHUNK_SIZE))
.map(chunk => {
const [Name, Address, Phone, Course] = chunk;
return {Name, Address, Phone, Course};
})
.reduce((text, record) => {
text += Object.keys(record).map(key => `${key} ${record[key]}`).join('\n') + '\n';
return text;
}, '');
} catch (err) {
textArea.innerHTML = 'Problem occurred: ' + err.message;
}
}

Not finding an easy solution to unban command for Discord Bot

I have been trying to get the unban command to work for the past 2 days, but I haven't found an easy solution for it, I keep getting errors like ".find()" isn't a function, or can't define "id". And I just don't get what I need to do. PS.: I am a noobie when it comes to code.
It's also worth mentioning that I have gone through many variations of this code and I have ended at this, probably previous iterations of the code were closer to the actual solution.
const Discord = require('discord.js');
const client = new Discord.Client();
const prefix = "+";
client.on('ready', () => {
console.log(`Logged in as ${client.user.tag}!`);
});
client.on('message', msg => {
const { content } = msg;
if (!content.startsWith(prefix)) return;
const args = content.slice(prefix.length).trim().split(/ +/g);
const command = args.shift().toLowerCase();
switch(command) {
case "ping" : {
let latency = Date.now() - msg.createdTimestamp;
let latencyOfAPI = Math.round(client.ws.ping);
msg.reply("This is the latency between the message and the response: " + latency + "." + "\nThis is the API latency: " + latencyOfAPI + ".");
break;
}
case "pong" : {
msg.reply("ping");
break
}
case "ban" : {
const user = msg.mentions.members.first();
if (user) {
msg.guild.members.ban(user);
msg.reply("The user " + user + " has been banned.")
} else {
return msg.reply("There is no one to ban.").catch(console.error);
}
break
}
case "unban" : {
const user = client.users.cache.find(user => user.username == "").id;
let banList = msg.guild.fetchBans();
if(banList = 0) {
return msg.reply("This user isn't in the community, or he is not banned.");
} else {
banList.find(user)
msg.guild.members.unban(user);
msg.reply("User " + user + " has been unbanned.")
}
break
}
}
});
client.login('.....');
Try this:
case "unban" : {
const user = client.users.fetch(args[1]).catch((err) => console.log(err));
user.then((u) => {
if (!args[1]) {
return msg.reply("Enter ID to unban")
} else {
if (u) {
msg.guild.members.unban(u).then(() => {
msg.reply("The user " + u.username + " has been unbanned.")
}).catch((err) => console.log(err))
} else {
return msg.reply("Cannot Find User")
}
}
})
break
Usage: [prefix]unban [ID] e.g [prefix]unban 3426743678738 (type in text channel)
Tip #1: Try to use .then() & .catch() on function which return a promise. You can use .then() to confirm that you've successfully unbanned a user and .catch() to see why there was a issue with unbanning a user.
Tip #2: Make an if statement which checks if the user running this command has the right permissions before trying the code i.e BAN_MEMBERS & ADMINISTRATOR
Also Note: .fetchBans() returns a collection and Promise

Discord.js for loop behaving oddly

I'm working on a kick command for a Discord bot in Discord.js. How it works is a previous function passes an array of user IDs to attempt to kick from the server. For some reason, the for loop is repeating more than it should and the i value doesn't seem to change sometimes.
Here's my code:
exports.kick = async (guild, targets, member, reason, bot) => {
var modRoleQuery = await exports.queryModRole(guild, member, bot);
var outputMessage = '';
if (modRoleQuery === false && !member.hasPermission('ADMINISTRATOR') && member != guild.me) return `You do not have permission to execute this command.`;
else if (targets.length === 0) return `Command usage: ${config.prefix}kick <#mentions/IDs> [reason]`;
else if (!guild.me.hasPermission('KICK_MEMBERS')) return `I require the \`Kick Members\` permission to execute this command.`;
else if (targets.length > 10) return `You may only kick 10 members at a time.`;
else if (reason.length > 1000) return `The kick reason must not exceed 1000 characters. Currently, it is ${reason.length}.`;
for (i = 0; i < targets.length; i++) {
console.log(`checking ${targets[i]}, ${i}`);
let targetMember = guild.member(targets[i]);
if (targetMember) {
if (targetMember.kickable) {
let targetMemberModRole = await exports.queryModRole(guild, targetMember, bot);
if ((targetMemberModRole || targetMember.hasPermission('ADMINISTRATOR')) && !member.hasPermission('ADMINISTRATOR')) {
outputMessage += `Unable to kick \`${targetMember.user.tag}\`: Only administrators can kick people with the moderator role and/or admin perms.\n`
} else {
await targetMember.user.send(`You were kicked from ${targetMember.guild.name} by ${member.user.tag}:\nReason: \`${reason}\``).catch(err => {});
await targetMember.kick(`[${member.user.tag}] ${reason}`);
exports.modLogEvent(bot, guild, `KICK`, targetMember.user, member.user, reason);
outputMessage += `Successfully kicked \`${targetMember.user.tag}\`\n`;
}
} else {
outputMessage += `Unable to kick \`${targetMember.user.tag}\`: I don't have permission to kick them.\n`;
}
} else {
outputMessage += `Unable to kick \`${targets[i]}\`: They don't seem to be in this server.\n`;
console.log(`${targets[i]} is not a member`)
}
}
outputMessage += `**Kick Reason:**\n\`${reason}\``;
return outputMessage;
}
When the size of the array is 1, this works as expected, however when it is more than 1, it doesn't. I've put in some console.log() functions for debugging purposes.
For some reason, the i value gets stuck on 1. I also ran it a bit earlier (this is before I added the console.log()s) and it behaved even more oddly:
I've been trying to debug this for over a day now and I'm not getting anywhere. Any assistance would be greatly appreciated.

How to fix ReferenceError

After some modification, instead of message is not defined, it is receivedMessage.channel.bulkdelete(args[0].then (() => {
ReferenceError: receivedmessage is not defined. I am not really sure myself what does that mean because im new to node.js and javascript. If there is any mistakes I made please tell me!
client.on('message', (receivedMessage) => {
if (receivedMessage.author == client.user) { // Prevent bot from responding to its own messages
return
}
if (receivedMessage.content.startsWith("?")) {
processCommand(receivedMessage)
}
})
function processCommand(receivedMessage) {
let fullCommand = receivedMessage.content.substr(1) // Remove the leading exclamation mark
let splitCommand = fullCommand.split(" ") // Split the message up in to pieces for each space
let primaryCommand = splitCommand[0] // The first word directly after the exclamation is the command
let arguments = splitCommand.slice(1) // All other words are arguments/parameters/options for the command
console.log("Command received: " + primaryCommand)
console.log("Arguments: " + arguments) // There may not be any arguments
if (primaryCommand == "help") {
helpCommand(arguments, receivedMessage)
} else if (primaryCommand == "multiply") {
multiplyCommand(arguments, receivedMessage)
} else if(primaryCommand == "clear") {
clearCommand(arguments, receivedMessage)
} else {
receivedMessage.channel.send("I don't understand the command. Try `?help`, `?multiply` or '?clear'")
}
function helpCommand(arguments, receivedMessage) {
if (arguments.length > 0) {
receivedMessage.channel.send("It looks like you might need help with " + arguments + ".Try `!multiply 2 4 10` or `!multiply 5.2 7`")
} else {
receivedMessage.channel.send("I'm not sure what you need help with. Try `?help [topic]`")
}
}
function multiplyCommand(arguments, receivedMessage) {
if (arguments.length < 2) {
receivedMessage.channel.send("Not enough values to multiply. Try `!multiply 2 4 10` or `!multiply 5.2 7`")
return
}
let product = 1
arguments.forEach((value) => {
product = product * parseFloat(value)
})
receivedMessage.channel.send("The product of " + arguments + " multiplied together is: " + product.toString())
}
}
function clearCommand (arguments, receivedMessage) {
if (!recievedMessage.member.hasPermission("MANAGE_MESSAGES"))
return receivedmessage.reply("You have no permission to use this command.Sad.");
if (!args[0])
return receivedMessage.channel.send("Please specify a number.")
}
receivedmessage.channel.bulkDelete(args[0]).then(() => {
receivedMessage.channel.send(`Cleared ${args[0]} messages.`).then(msg => msg.delete(5000));
}
,)
You need to use receivedMessasge instead of message, as thats the name you choose in that function.
It kinda seems like you dont really have much experience and I would recommend you to read the offical discord.js guide: https://discordjs.guide . It will teach you how to write Discord Bots without needing to copy a lot of weired stuff into your Code!
1) You have defined receivedMessage instead of messsage
2) The code for clear command is not in any function and it executes once, before any messages.
You need to use receivedMessage instead of message and insert the code in the processCommand function
if (primaryCommand == "help") {
helpCommand(arguments, receivedMessage)
} else if (primaryCommand == "multiply") {
multiplyCommand(arguments, receivedMessage)
} else if(primaryCommand == "clear") {
if (!message.member.hasPermission("MANAGE_MESSAGES")) return message.reply("You have no permission to use this command.Sad.");
if (!args[0]) return message.channel.send("Please specify a number.")
message.channel.bulkDelete(args[0]).then(() => {
message.channel.send(`Cleared ${args[0]} messages.`).then(msg => msg.delete(5000));
});
// or create a function for this command
} else {
receivedMessage.channel.send("I don't understand the command. Try `?help` or `?multiply`")
}

Categories

Resources