How to make a function in Node JS run only once - javascript

I am creating a simple tictactoe terminal game in JS. I use the variable named player1Input to get user prompt. If the prompt is not equal to "X", I call the function again to make sure the user input the right input. If I enter the wrong input multiple times, the function (player1Game) ends up being called multiple times instead of once. How do I get it to just be called once. I put a snippet of my code at the bottom.I commented the part of the code that makes the function run twice
function player1Game () {
let player1Input = prompt(`${player1Name.charAt(0).toUpperCase() + player1Name.slice(1) } please enter \"x\": `);
//Create an error that responds if player 1 does not type x
if (player1Input !== "x") {
console.log("Please make sure you type in x")
player1Game();
//the function runs multiple times here instead of once.
// How do I get it to run only once.
}

You still aren't showing the whole context here, but perhaps you just need to return after you call it again so that the rest of the function doesn't execute when the function doesn't meet the input requirements:
function player1Game () {
let player1Input = prompt(`${player1Name.charAt(0).toUpperCase() + player1Name.slice(1) } please enter \"x\": `);
//Create an error that responds if player 1 does not type x
if (player1Input !== "x") {
console.log("Please make sure you type in x")
player1Game();
// return so it doesn't execute any more of the function
return;
}
// code here will only get called if the `player1Input`
// meets the above critera
// Rest of your code here...
}
Or, you could use an if/else:
function player1Game () {
let player1Input = prompt(`${player1Name.charAt(0).toUpperCase() + player1Name.slice(1) } please enter \"x\": `);
//Create an error that responds if player 1 does not type x
if (player1Input !== "x") {
console.log("Please make sure you type in x")
player1Game();
} else {
// code here will only get called if the `player1Input`
// meets the above critera
// Rest of your code here...
}
}
FYI, there's nothing special here. This is just normal function control flow in Javascript. If you want no more of the function to execution then insert a return statement. Or protect branches of code with an if/else so a condition will control what code executes.

Related

postman.setNextRequest failing to call

I have a collection of tests which I am trying to set up to run in a certain sequence. The sequence is decided using if/else if statements which check a variable in a data-file and set the next request depending on its value.
This works well for the initial request in my collection. But when it gets to a request later in the sequence, the if statement will recognize the correct variable but skip over the postman.setNextRequest() command and run the test below it in the collection order instead of running the specified test.
Does anyone know why this is happening? Seems like a bug with the postman.setNextRequest() function.
Request where function is working as expected:
var rsp = pm.response.json();
var base = pm.environment.get('baseUrl');
pm.environment.set('id', data['appName']);
var id = pm.environment.get('id');
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
pm.test("Response contains correct BaseUrl", function(){
var issuer = rsp.issuer;
pm.expect(issuer).to.contain(base);
//console.log(resName);
console.log('Passed - on to the next one!')
});
});
if (id === 'Application/Member_PRODUCTION'||id === 'Application/B2C_PRODUCTION'||id === 'Application/Claims Transformation_PRODUCTION'){
postman.setNextRequest('PKCE Step 1- Generate PKCE Challenge and Verifier');
}
else if (id === 'Application/sysTest_SysTest2_PRODUCTION'){
postman.setNextRequest("oAuth Step 1 - Unauthorised API call");
}
else{
postman.setNextRequest("oAuth Step 2- Get Session Data Key");
}
Next request where the function fails to work:
let cookieJar = pm.cookies.jar();
cookieJar.clear(pm.environment.get('baseUrl'));
var id = pm.environment.get('id');
console.log('oAuth check complete for application: '+ id);
pm.test("Status code is 302", function () {
pm.response.to.have.status(302);
console.log('Passed - on to the next one!')
});
if (id === 'Application/Member_PRODUCTION'){
console.log('Next Up - SCIM Tests')
postman.setNextRequest("SCIM Step 1 - Create Member");
}
else{
console.log('Next Up - Login Page Test')
postman.setNextRequest("Login Page Step 1- Get Session data key");
}
The request names were copied straight from the requests themselves so I don't believe that it cannot find the specified next request and the usage in both snippets above seems to be the same so I am a little stuck.

Web BLE Characteristic startNotifications sometimes doesn't bind

I'm using web BLE. I have based my code according to the example of the heart rate measurement.
Everything is working fine most of the time. But sometimes, even if the connection is successfully made, when I try to bind to the notification, it doesn't work.
The link is made in this function :
_startNotifications(characteristicUuid) {
let characteristic = this._characteristics.get(characteristicUuid);
console.log(characteristic);
return characteristic.startNotifications().then(() => characteristic);
}
When everything is OK, I can see in the console that BluetoothRemoteGATTCharacteristic has a value : DataView(2) {}
Otherwise, when it's not working it has a value : null
I would like to be able to retry automatically, if I detect that the value is null. But I'm not familiar with Promise (I think this is it) and console.log(characteristic.value) doesn't work here.
How would you approach this ?
What I ended up doing is "bypass" the issue. So it's a more algorithmic resolution than a pure Javascript one.
I didn't change the connection function, so it is still called like this :
device._startNotifications(some_uuid).then(handleHeartRateMeasurement)
I check everything in the handleHeartRateMeasurement function :
var ready = false;
function handleHeartRateMeasurement(heartRateMeasurement) {
console.log("Hold on...");
heartRateMeasurement.addEventListener("characteristicvaluechanged", event => {
// Everytime the value change, this should be triggered
// If it did not, variable "ready" will stay false
ready = true;
var value = device.parseValue(event.target.value);
// Do something with value here
});
var check = function(){
// If we have received data from characteristic, we are ready to go !
if(ready === false){
console.log("Device connected but not receiving data");
// Stop the current notification subscription
device.stopNotificationsHeartRateMeasurement();
// Start a new one
device._startNotifications(some_uuid).then(handleHeartRateMeasurement);
setTimeout(check, 1000); // check again in a 1s
}
else{
console.log("Device connected and receiving data");
}
}
setTimeout(() => {
check();
}, 500);
}

Discord.js - Trying to both await an async process and allow recursive calls of a wrapper

This one has a ton of moving parts that I've tried to simplify down as much as possible, and I still learning about async/await processing, so bear with me -
So I'm trying to write chat commands for a Discord chatbot with discord.js. The command that I'm having trouble with, triggered by a message beginning in !aut, is supposed to take in a string of user input (that follows the command itself) and return another string; if the user does not provide a string, I want it to grab the content of the message immediately above the message containing the command (i.e. 2nd most recent) and use that as the input string.
However, testing this latter case, it keeps throwing this error:
(node:17896) UnhandledPromiseRejectionWarning: DiscordAPIError: Cannot send an empty message
I've structured the bot with an event listener that listens for commands and calls the wrapper function execute(string, channel) if it detects one; the wrapper then calls the appropriate utility function for that command to get a string that in then passes back to the listener, which then sends the string out to the channel.
The utility function com_aut(array) is working perfectly fine; the problem is that the default empty string sComResult defined within the wrapper is being returned to the listener before it can be overwritten by com_aut:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
let sResult = execute(pMessage.content, pMessage.channel);
pMessage.channel.send(sResult);
}
});
function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pChannel.fetchMessages({ limit: 2 }).then(pMessages => {
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
TextChannel.fetchMessages is asynchronous - or returns a Promise, at least - so I tried making the wrapper asynchronous as well so I could force it to await. Plus the necessary changes in the listener, I found that this worked:
client.on('message', pMessage => {
if (executable(pMessage.content) == true) {
execute(pMessage.content, pMessage.channel).then(sResult => { pMessage.channel.send(sResult) });
}
});
async function execute(sMessage, pChannel = null) {
// strip off the initial ! that marks the message as a command; whatever comes immediately afterwards is the command
let args = sMessage.substring(1).trim().split(/ +/g);
let cmd = args[0];
// don't include the command itself among the rest of the arguments passed to it
args = args.splice(1);
let sComResult = "";
switch(cmd){
...
case "aut":
if (args.length < 1) {
// input string that should be in args actually isn't, so grab the content of the 2nd most recent message instead
pMessages = await pChannel.fetchMessages({ limit: 2 });
sComResult = com_aut([pMessages.last().content]);
});
} else {
// input string is present in args, so just use that
sComResult = com_aut(args);
}
break;
}
return sComResult;
}
However, NOW the problem is that I can't call execute(string, channel) recursively, which I do when piping the output of one string-output command into another, string-input command. (Which is also why the wrapper exists in the first place instead of the listener just being linked directly to the utility functions) This involves an execute call within execute itself. I'll just link to pastebin at this point, but it's throwing a type error since it's not able to get a value back from the nested execute and so it ends up trying to call null.then:
(node:6796) UnhandledPromiseRejectionWarning: TypeError: pInnerPromise.then is not a function
How can I structure my code so that it properly awaits the fetchMessages query before moving on, but still allowing recursive calling of the wrapper function (or some other way to pipe)?
Your code
if (executable(sInnerCom) == true) {
// here you are using await so promise is already resolved.
let pInnerPromise = await execute(sInnerCom, pChannel);
// no need to use then, you can return result direct
pInnerPromise.then(result => { sInnerComResult = result });
}
It should be like this
if (executable(sInnerCom) == true) {
let result = await execute(sInnerCom, pChannel);
sInnerComResult = result ;
}
or like this
if (executable(sInnerCom) == true) {
sInnerComResult = await execute(sInnerCom, pChannel);
}

Why aren't i successfully getting the embedded "if" in the second code section to do its job?

var checking_location = "none"
const getentitiesByType = (arr, type) => {
for (let i in arr) {
if (arr[i].type === type) {
checking_location = "exists"
return arr[i].entity
}
}
return null;
}
if (!meeting.location) {
if (checking_location != 'exists') {
rl.question('where is the location ', function(answer) {
// session.send("The location you gave:" answer);
rl.close();
session.send(answer)
// console.log(tryagain(answer, 'Calendar.Location'));
session.send(tryagain(answer, 'Calendar.Location'));
});
}
} else {
next();
}
What i'm trying to do here is to have a loop in the if (!meeting.location) if checking_location stays equal to none. Basically i want to check if a certain Json field exists, if it doesn't i want to keep asking the question in rl.question.My issues is that the code is only working the first time, then even if i give another input not containing the required field i don't get that question.Also note that this is not the entire code but it's more than enough to understand the possible issue spots in my implementation.
getentitiesByType needs to be called somewhere, simply assigning it to a variable will not make the function run: getentitiesByType(youArr, yourType).
Also, as a side note, instead of using string values for checking_location just rename the variable and use a boolean value. Ex: var hasLocation = false.

Javascript/JQuery wait for user input

I'm working on a text-based browser game made using Javascript and JQuery.
I've run into a problem with user input.
What I used to do was just use a prompt() because it was easy to use, allowed me to save the input to a variable and made the code wait for input.
Now I want it to look better, so I've made my own input field with a nice chatbox above it.
What I wanted to know was how to stop the code from executing untill the user has pressed enter (I already detect the enter press and the text is being appended to the dialog box, I just need the code to wait for that to happen before it continues).
Here's some of my code:
Function for input
function input_field() {
var inputField = $('#dialog-input');
var messageField = $('#dialog-text');
inputField.keyup(function (e) {
if (e.keyCode == 13) {
window.userInput = inputField.val();
if(userInput != '') {
messageField.append('You: ' + window.userInput + '<br>');
inputField.val('');
messageField.scrollTop(999999999);
}
}
});
}
What I'd like to do is just save the data to a variable and then check it with a switch-case just like with prompt(), but as it stands now it just gives me an error because it tries to execute all the code instead of wait untill the user has given input.
It is possible with asynch+await.
Please note, that it is currently not fully supported by all browsers (http://caniuse.com/#search=await) and that there are probably better solutions to this kind of problems.
Using await myAsyncFunction() makes the browser treat the function like it is synchrounous, therefore it stops further execution of this function until a result is returned by the awaited function. It does not block other code on the website from running.
await may only be used inside a async function, otherwise the browser will throw an error.
Here is an example showing how you could wait for user input with await+async:
async function handleForm() {
let userInput = '';
console.log('Before getting the user input: ', userInput);
userInput = await getUserInput();
console.log('After getting user input: ', userInput);
};
function getUserInput() {
return new Promise((resolve, reject) => {
$('#myInput').keydown(function(e) {
if (e.keyCode == 13) {
const inputVal = $(this).val();
resolve(inputVal);
}
});
});
};
handleForm();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<input id="myInput">
You have to thing differently, while javascript stop and wait for a returned value when using prompt(), you can't directly achieve that with a custom prompt.
var result = [];
for(var i = 0; i > 5; i--){
result.push( prompt('tip something') ); // Ok
};
javascript will break until prompt return something
but you can't tell your code to stop, like the browser does when promprting. You'll have to execute a code when closing the modal (on button click or keypress enter) that open/update the next modal.

Categories