This is my code (Javascript):
function getNumbers(){
var numberString = document.getElementById("numbers").value;
var actualNumbers = [];
var flowIndex = 0;
for(let i = 0; i < numberString.length; i++){
if(numberString.charAt(i) != " " && numberString.charAt(i) != "\," && numberString.charAt(i) != "\t"){
actualNumbers[flowIndex] = parseInt(numberString.charAt(i));
flowIndex++;
}
else continue;
}
return actualNumbers;
}
function division(){
try{
var answer = getNumbers()[0] / getNumbers()[1];
if(getNumbers()[1] == 0)
throw "bad";
}
catch(error){
throw error.description + "Division by zero error";
}
finally{
return answer;
}
}
I have a function getNumbers() which returns an array, with array[0] = 1 and array[1] = 0. Now, I want to throw an exception "bad" when array[1] == 0. But, neither the try exception nor the catch exception is being thrown, but the finally clause is working. What is the problem?
NOTE: On division by zero, no exception is being thrown, instead answer is coming out to be Infinity. getNumbers() is working properly.
The exception is getting thrown, but then you're suppressing the exception by doing this:
finally {
return answer;
}
The finally clause gets final say. If you return from it, that suppresses the exception and makes the function complete normally.
One way to fix it is to remove the finally clause and put the return answer; inside your try.
Just FWIW, some other notes as comments:
function getNumbers(){
var numberString = document.getElementById("numbers").value;
var actualNumbers = [];
var flowIndex = 0;
// You might consider splitting the string into an array of one-character strings so you
// aren't constantly calling a method (`charAt`), like this:
// `var chars = numberString.split("");`
// Then index into `chars`
// N.B. `let` is an ES2015 (ES6) feature not all JavaScript engines have as it's new;
// the rest of your code is using the older `var`
// --v
for (let i = 0; i < numberString.length; i++){
// No need to escape the comma --------------------------------v
if(numberString.charAt(i) != " " && numberString.charAt(i) != "\," && numberString.charAt(i) != "\t"){
actualNumbers[flowIndex] = parseInt(numberString.charAt(i));
flowIndex++;
}
// No need for the `else continue;` at all
else continue;
// In the above, you regularly call `charAt` four times when once would have been sufficient.
// You might also consider a `switch`
}
return actualNumbers;
}
function division(){
try{
// Rather than calling `getNumbers` three separate times, call it once and remember its return value
// doing the calculation should be AFTER checking [1] for 0, not before
var answer = getNumbers()[0] / getNumbers()[1];
if(getNumbers()[1] == 0)
throw "bad"; // Recommend using Error, e.g.: `throw new Error("bad")`
// Move the `return answer;` here
}
catch(error){
// You've thrown a string, it doesn't have a `description` property
// Separately: Why throw something above, just to catch it here and throw something else?
throw error.description + "Division by zero error";
}
// Remove the finally
finally{
return answer;
}
}
Again just FWIW, I'd probably put responsibility for getting the value from the input in division (or even in the thing calling division) rather than in getNumbers, and use /\d/.test(...) to test if a character is a digit, since there are lots of non-digits that aren't " ", ",", or "\t". And once we know they're digits, we can use +ch instead of parseInt to convert them (but with this input, it's just a style choice [well, there's a performance implication, but 99.99% of the time, that doesn't matter]).
So perhaps:
function getNumbers(str) {
var numbers = [];
str.split("").forEach(function(ch) {
if (/\d/.test(ch)) {
numbers.push(+ch);
}
});
return numbers;
}
function division() {
var numbers = getNumbers(document.getElementById("numbers").value);
if (numbers[1] == 0) {
throw new Error("Division by zero error");
}
return numbers[0] / numbers[1];
}
Or with an alternate getNumbers that is more concise, but makes more loops through the input (which usually doesn't matter):
function getNumbers(str) {
return str.split("")
.filter(function(ch) { return /\d/.test(ch); })
.map(function(ch) { return +ch; });
}
function division() {
var numbers = getNumbers(document.getElementById("numbers").value);
if (numbers[1] == 0) {
throw new Error("Division by zero error");
}
return numbers[0] / numbers[1];
}
Related
I've been scouring similar problems but haven't seem to have found a solution that quite works on my end. So I'm working on a Discord bot that takes data from a MongoDB database and displays said data in the form of a discord embedded message using Mongoose. For the most part, everything is working fine, however one little section of my code is giving me trouble.
So I need to import an array of both all available users and the "time" data of each of those users. Here is the block of code I use to import said data:
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
Now this for loop references a function I made called getData which obtains the data from MongoDB by this method:
async function getData(field, value){
var data;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
data = result[value];
}
});
if(field == "user"){
return data.user;
}else if (field == "time"){
return data.time;
}else{
return 0;
}
So that for loop is where my errors currently lie. When I try to run this code and display my data through a discord message, I get this error and the message does not get sent:
(node:13936) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'time' of undefined
Now the strange thing is, this error does not happen every time. If I continue calling the command that triggers this code from my discord server, it's almost like a 50/50 shot if the command actually shows the message or instead gives this error. It is very inconsistent.
This error is confounding me, as the undefined part does not make sense to me. The objects that are being searched for in the mongoDB collection are definitely defined, and the for loop never exceeds the number of objects present. My only conclusion is that I'm doing something wrong with my asynchronous function design. I have tried altering code to use the getData function less often, or to not use awaits or asynchronous design at all, however this leaves my final discord message with several undefined variables and an eventual crash.
If anyone has any advice or suggestions, that would be very much appreciated. Just for reference, here is the full function that receives the data, sorts it, and prepares a string to be displayed on the discord server (though the error only seems to occur in the first for loop):
async function buildString(){
var string = "";
var totalObj;
var timeArray = [];
var userArray = [];
var stopSort = false;
await stats.find({}, function(err, result){
if(err){
result.send(err);
}else{
totalObj = result.length;
}
});
for (i = 0;i < totalObj; i++){
timeArray[i] = await getData('time', i);
userArray[i] = await getData('user', i);
}
while(!stopSort){
var keepSorting = false;
for(i = 0; i < totalObj ; i++){
var target = await convertTime(timeArray[i]);
for(j = i + 1 ; j < totalObj ; j++){
var comparison = await convertTime(timeArray[j]);
if(target > comparison){
//Switch target time with comparison time so that the lower time is up front
var temp = timeArray[i];
timeArray[i] = timeArray[j];
timeArray[j] = temp;
//Then switch the users around so that the user always corresponds with their time
var userTemp = userArray[i];
userArray[i] = userArray[j];
userArray[j] = userTemp;
//The loop will continue if even a single switch is made
keepSorting = true;
}
}
}
if(!keepSorting){
stopSort = true;
}
}
//String building starts here
var placeArray = [':first_place: **1st', ':second_place: **2nd', ':third_place: **3rd', '**4th', '**5th', '**6th', '**7th', '**8th', '**9th', '**10th'];
for(i = 0; i < totalObj; i++){
string = await string.concat(placeArray[i] + ": " + userArray[i] + "** - " + timeArray[i] + " \n\n");
console.log('butt');
}
console.log("This String:" + string);
return string;
}
I think problem is you are trying to await function with callback, it will not work => access to data.time may run before data = result[value]. If you need await callback, you can use custom Promise (or use util.promisify, more info here)
Promise:
function findStats(options) {
return new Promise((resolve, reject) => {
return stats.find(options, function (err, result) {
if (err) {
return reject(err)
}
return resolve(result)
})
})
}
utils.promisify
const util = require('util');
const findStats = util.promisify(stats.find);
Now you can use await in your function
async function getData(field, value) {
try {
const result = await findStats({})
const data = result.value
if (field === 'user') {
return data.user
}
if (field === 'time') {
return data.time
}
return 0
} catch (error) {
// here process error the way you like
// or remove try-catch block and sanitize error in your wrap function
}
}
as said on title, validating the prompt if is null (inpname variable) inside the func/while/try wont work. output = {}
meanwhile the testing i did outside works fine.
check the code below please. what did i do wrong?
//works
let test = prompt("testing","aasdasd");
if (test === null) {
console.log("cancel");
}
else {
console.log("ok");
}
let inpname;
//do not work
let func = () => {
while (true) {
try {
inpname = prompt("name ", "name here");
if (inpname.length > 10 || inpname.length <= 3) {
throw "Your name must be at least 10 characters long, but not less than 4";
}
else if ( inpname != inpname.match(/^[a-zA-Z]+$/)) {
throw "A-Z characters accepted only!";
}
//problem here!
else if (inpname === null) {
throw "cant cancel";
}
else {
console.log("success");
break
}
}
catch (err) {
console.log(err);
break
}
}
}
func();
The console outputting {} instead of the exception seems to be a bug in Stack-snippets. You would get more correct output using console.error.
That being said, the issue you're seeing is in part caused because you're not checking that impname is null before you attempt to dereference it.
Changing the ordering of your error checking would solve the problem (Although stack-snippets is still not going to report exceptions as they happen, which is not the behavior you get in a browser)
let func = () => {
while(true) {
var inpname = prompt("name ", "name here");
try {
if (inpname === null) {
throw "cant cancel";
}
if (inpname.length > 10 || inpname.length <= 3) {
throw "Your name must be at least 10 characters long, but not less than 4";
}
if (inpname != inpname.match(/^[a-zA-Z]+$/)) {
throw "A-Z characters accepted only!";
}
return inpname;
} catch(err) {
console.error(err);
}
}
}
func();
Note that you might want to avoid disallowing use of the "cancel" button. If the user doesn't want to provide the requested info, simply exit the app with an appropriate message
I'm using the automated testing framework, Protractor.
I've come to find that Protractor frequently makes use of promises to asynchronously resolve code evaluation.
Question: How can I manually resolve a promise to a specific value, once a condition is met?
Update: 09/08/2017
Sorry, I was just a bit unclear on promises. I was able to get this working correctly now with:
// match variable
var match = false;
// get all elements with `div` tag
var scanElements = element.all(by.css('div')).each(function(el) {
// get text content of element
el.getText().then(function(text) {
// split words into array based on (space) delimeter
var sp = text.split(' ');
for (var i = 0; i < sp.length; i++) {
if (sp[i] == 'Stack Overflow') {
match = true;
}
}
});
});
// on complete
scanElements.then(function() {
if (match) {
console.log('Status: Found match!');
}
else {
console.log('Status: No match');
}
});
You should use map instead of each. If you look at the source code, this is how each is implemented:
each(fn: (elementFinder?: ElementFinder, index?: number) => any): wdpromise.Promise<any> {
return this.map(fn).then((): any => {
return null;
});
}
So, as you can see it internally uses map and hides the result by returning null. It is also pointed out in the documentation.
Also rename element to something else just to avoid ambiguity with protractor's element object.
There is no issue here according to the documentation the return type of element.all().each() is null after it iterates through everything.
A promise that will resolve when the function has been called on all the ElementFinders. The promise will resolve to null.
Edit 1:
Is filter a valid option?
element.all(by.css('div'))
.filter(function(element) {
return element.getText().then(function(text) {
var sp = text.split(' ');
for ( var i =0; i< sp.length; i++) {
if(sp[0] == 'protractor') return true;
}
return false;
});
}).first();
Will first filter and then return first element that matches
In your exact example you can use .getText() on ElementArrayFinder -
// calling .getText() exactly on ElementArrayFinder returns promise
let hasStackOverflow = $$('div').getText().then(texts=> {
// texts would be array of strings
return texts.includes('Your Text exact match')
})
hasStackOverflow.then(has=> {
if (has) {
console.log('Status: Found match!');
}
else {
console.log('Status: No match');
}
})
I 'm currently having a hard time figuring out why an object is once defined and on the next line it is not.
In my code, I'm declaring a promise with a for loop inside, that loops through a couple of file inputs and checks the files(images) dimension.
Once all inputs are processed the promise is resolved and the then method fires.
for(var i = 0; i < $('.apk-wrapper .mandatoryImg').length; i++){
if ($('.apk-wrapper .mandatoryImg')[i].value){
var id = $($('.apk-wrapper .mandatoryImg')[i]).attr('id');
var imageProcessing = new Promise(function(resolve,reject){
if(id == 'game_icon'){
imageProcessor($('.apk-wrapper .mandatoryImg')[i],512,512)
}
else if(id == 'ingame1'){
imageProcessor($('.apk-wrapper .mandatoryImg')[i],720,1280)
}
...
else{
error = true;
reject()
}
if(i == $('.apk-wrapper .mandatoryImg').length - 1){
resolve(images)
}
}
}).then(function(images){
console.log(images)
// console.log(images.length)
})
If I now log the array of processed images I get the correct Object with indexes.
Array[0]
0:File
1:File
2:File
3:File
4:File
5:File
length:6
When I try to get the length of that object, I tried multiple methods(.length, while hasOwnProperty, for keys in x), I always get back 0.
To get a Promise that's resolved only when all of the files are processed, try this (assuming that imageProcessor itself returns a Promise):
var promises = $('.apk-wrapper .mandatoryImg').map(function(i, el) {
var id = el.id;
if (id === 'game_icon') {
return imageProcessor(el, 512, 512);
} else if (id === 'ingame1') {
return imageProcessor(el, 720,1280)
} else if {
...
} else {
return Promise.reject();
}
}).get();
The $(...).map(...).get() chain obtains an array of Promises, one for each element in the jQuery collection.
You can then wait for all those Promises to be resolved before proceeding:
Promise.all(promises).then(function(images) {
...
});
timeseries is an array in the following format:
[ {"date": "2012-12-21", "price": 1.234}, ... ]
My code:
function first(timeseries) {
if (timeseries.length === 0) {
return undefined;
}
var earliestIndex = 0;
for (var i = 0; i < timeseries.length; i++) {
if (timeseries[i].date === null) {
throw new Error("no date");
} else {
if(Date.parse(timeseries[i].date) < Date.parse(timeseries[earliestIndex].date)) {
earliestIndex = i;
}
}
}
return timeseries[earliestIndex].price;
}
Test result:
The question did not specify the exact value of date when not provided.
Why is this so? I have already thrown an error.
Couple of suggestions to cover all cases.
Test if timeseries[i].price is null or not before returning.
You may want to try using == instead of === as it will also do the necessary type conversions before check.
Reference: https://stackoverflow.com/a/359509/4874271
Tip: COPY the code and format it here instead of posting photos, would be easier for people to answer. :)