Getting same result from function every time - javascript

why is my function returning the same result?
I would like to input all the values from the “ping” function to an array and then output that array in html.
I run the function 3 times but all three times the result is the same. Can you tell me why?
(The domains are just an example by the way, cant put originals here)
var str = ' ';
var t=[];
var n= 2;
var arr = ["www.google.com","www.example.com","www.example2.com"];
var results = [];
var finalurl = '';
function fun1(){
for (var i=0; i < arr.length; i++){
str = "http://" + arr[i] + "/images/";
finalurl = str + "image-l.gif" + "?id=" + (new Date()).getTime();
ping(finalurl);
textt += results[i] + " ";
$(‘#ping’).html(textt);
}
}
var ping = function(finalurl) {
var l = 0;
t.push((new Date()).getTime());
if(t.length > n) {
p=t[2]-t[1];
results.push(p);
}
else {
var img = new Image;
$(img).load(function() {
ping();
}).attr('src', finalurl);
}
}
//small part of html:
<h2>run</h2>
<h1 id=“ping”> </h1>

This generates three urls (the length of arr) but only attempts to show two (the value of n). The urls are different each time, but you are limiting them in ping so the new ones are not used.
Try setting n to higher number, you will see it will load more images each click - as it currently stands it tries to load more in a single click (3) than it allows (2).
Note: even if those urls are different, the images may be the same, this happens if the server ignores the id parameter... which probably does as it requires additional configuration for the server to handle requests to a ".gif" resource (which is not a known servcer side scripting language) - by default the server will just return the resource image-l.gif.
By the way: At $(‘#ping’) those are the wrong quotes. Also textt is not defined - I did define it as var textt = ''; for my tests.

Related

JavaScript Loop Animation Interval

I'm trying to get this loop to return a value, for each value in an array every 1 second.
The returned value is a random value generated earlier, and each loop will add i to the number and output it. (ran[0]+i) (ran[1]+i) etc.
I need the output in the same order as my example, but with a 1 second interval and something to generate my returns/consolelogs instead of having to type in all 4, or however many I use (could be random).
The code is for an animation but I cannot get the SVG working here and its irrelevant to the problem I think.
var ran = [];
var qan = 4;
for(i=0;i<(qan);i++){
rd = Math.floor(Math.random()*360);
ran.push(rd);
};
for(i=0;i<10;i++){
/*need to have (random.length) number of console logs and interval loops by 1 second*/
console.log((ran[0]+i) + " loop " + (i));
console.log((ran[1]+i) + " loop " + (i));
console.log((ran[2]+i) + " loop " + (i));
console.log((ran[3]+i) + " loop " + (i));
};
You may do like this;
var ran = [];
var qan = 4;
for(let i=0;i<(qan);i++){
rd = Math.floor(Math.random()*360);
ran.push(rd);
setTimeout(function(){console.log(ran[i])},1000*i);
}
Or by using var instead of let you can still do like this by utilizing an IIFE to return a callback with an encapsulated i value.
var ran = [];
var qan = 4;
for(var i=0;i<(qan);i++){
rd = Math.floor(Math.random()*360);
ran.push(rd);
setTimeout((function(j){ return function(){ console.log(ran[j]) } })(i),1000*i);
}
Update: I hope i am getting closer.. I just console.log the array itself but the items increase by i in each round. (10 rounds / frames)
var randar = new Array(4).fill().map(e => ~~(Math.random()*360));
console.log("starting random array ",randar); // let's see how the random array starts
for (let i = 0; i < 10; i++){
setTimeout(function(){console.log(randar.map(e=> e+i))} ,1000*i);
}
Note: I use arrows mostly but if you have concerns about IE or Safari then it's best to replace them with conventional function calls.

AngularFire: $add sets fbUID and custom UID, why?

Before there are any questions, I have a function that creates a custom UID because I don't "need" the long Firebase UID and wanted something shorter which is more easy to remember.
Anyway, in my create-function I'm not sure I'm adding it to the db correctly.
Here's a snippet and below that is how it looks in my database.
$scope.create = function(){
// Generate a shorter random uid (6 chars) that replaces the long regular Firebase uid
letters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
uid_length = 6;
generator = function(){
random = '';
for(var i = 0; i < uid_length; i++){
random += letters.charAt(Math.floor(Math.random() * letters.length));
}
return random;
}
generator();
var lists = new Firebase('https://url.firebaseio.com/lists/' + random);
firebaseLists = $firebaseArray(lists);
//lists.child(random).set(random);
firebaseLists.$add(random).then(function(lists){
})
This gives me, for example:
lists
0Knn8M <- custom UID
-KH6kSxPAaerjU: '0Knn8M'
As I want the things that are added to 0Knn8M displayed on my page, it also displays the FB UID. Of course I could do a CSS 'display:none;' on that child but shouldn't it be another way around it?
I think, that here is an error:
generator = function(){
random = '';
for(var i = 0; i < uid_length; i++){
random += letters.charAt(Math.floor(Math.random() * letters.length));
}
return random;
}
generator();
var lists = new Firebase('https://url.firebaseio.com/lists/' + random);
You are calling generator() but not assigning it result to any variable. In var lists = new Firebase('https://url.firebaseio.com/lists/' + random); the variable random is now undefined. So firebase generates it's own id I guess.
So you need to change just one thing var random = generator().

How can I load some JSON into my web application with JavaScript and select a random word?

I have a file that I have saved as words.json that is a large list of words, ordered alphabetically and by length.
They are structured like this:
{"3":["ace","act","add","ado","ads"], "4":[...], ...}
(For brevity I added the ellipsis)
How can I load the JSON to the page and select a random word on the list? Do I need jQuery? What should my function look like?
Thank you!
You could do something like this:
function getRandomWord(jsonStringListOfWords) {
var words = JSON.parse(jsonListOfWords);
var MAX_LENGTH = Object.keys(words).length;
var wordLength = Math.floor(Math.random() * MAX_LENGTH) + 1;
var wordIndex = Math.floor(Math.random() * words[wordLength].length) + 1;
return words[wordLength][wordIndex];
}
Where it first chooses the length of the word randomly, then one of those words from the list of words of that length. This, as ScottSauyet pointed out in the comments, will not give you an even distribution between all words of varied length.
Here's an example of an algorithm which gives an even distribution for all words, regardless of length:
function getRandomWordEvenDistribution(jsonStringListOfWords) {
var words = JSON.parse(jsonListOfWords);
var numWords = 0;
for (var x in words) {
numWords += words[x].length;
}
var wordIndex = Math.floor(Math.random() * numWords);
for (var x in words) {
if (wordIndex >= words[x].length) {
wordIndex -= words[x].length;
} else {
return words[x][wordIndex];
}
}
}
As far as actually loading the JSON, if you are willing to use jQuery, it has a very nice method called $.getJSON(), which you can use to grab the JSON string from your server.
I was able to get it to work with Mash's algorithm (I made two minor fixes to it, and updated that answer with them.) You're right about the JSON.parse being unnecessary with jQuery's getJSON. It's running on JSBin:
var words = (function() {
var wordList, numWords;
return {
load: function(data) {
wordList = data;
numWords = 0;
for (var x in wordList) {
numWords += wordList[x].length;
}
words.random = function() {
var wordIndex = Math.floor(Math.random() * numWords);
console.log(wordIndex);
for (var x in wordList) {
if (wordIndex >= wordList[x].length) {
wordIndex -= wordList[x].length;
} else {
return wordList[x][wordIndex];
}
}
};
},
random: function() {
return undefined; // or throw exception? // not initialized yet
}
};
}());
var print = (function() {
var $console = $("#console");
return function(msg) {
$console.text($console.text() + "\n" + msg);
};
}());
$("#random").click(function() {
print("Random word: " + words.random());
});
print("Random word before load: " + words.random());
$.getJSON("http://jsbin.com/ukaxec/2/js")
.then(words.load)
.then(function() {print("Random word after load: " + words.random());});
The $.getJSON() call is just calling a small list of words, a minimal extension of your example, also hosted on JSBin.
Note that before the JSON is successfully loaded, the function words.random is just a dummy function, which gets overridden once the words are in place.
But I still wonder, if you're only going to use this to load a single word, why you would bother to send the whole list down to the client.

textarea duplicate string check ignoring leading and trailing whitespace

Users will enter various serials in a textarea. Each newline will indicate a new serial. Some requirements/restrictions:
Leading and trailing white spaces are not allowed.
White space within a serial is okay.
Blank serials are not allowed
I'd prefer to not use JQuery.
Store duplicates so they can be shown to the user.
Based on my tests I have a working solution. I want to make sure I'm not missing or overlooking anything. My questions are:
Is there a more efficient ways to check for duplicates?
Are there any glaring test cases that my solution won't catch?
Working Example: http://jsbin.com/ivusuj/1/
function duplicateCheck() {
var output = document.getElementById('Output');
output.innerHTML = '';
var duplicateSerials = [];
var count = 0;
var textArea = document.getElementById('Serials');
var serials = textArea.value.trim().split(/ *\n */);
for(var i = 0;i < serials.length;i++){
var serial = serials[i];
if(serials.indexOf(serial) != serials.lastIndexOf(serial) &&
duplicateSerials.indexOf(serial) == -1 && serial !== '') {
duplicateSerials.push(serial);
}
}
// For testing
output.innerHTML = '<pre>Serials:\t' + serials.toString() + "<br />" +
'Duplicates:\t' + duplicateSerials.toString() + "<br>" +
'</pre>';
}
Note: the above is for a client side check. The same check will be performed server side as well to ensure the data is valid.
Update
Solution comparison: http://jsbin.com/ivusuj/4/edit
I put together a jsfiddle her: http://jsfiddle.net/wrexroad/yFJjR/3/
Actually checking for duplicates that way is pretty inefficient.
Instead of checking for duplicates, this just adds a property to an object where the property's name is is the serial. Then it prints out all of the property names.
This way if you have duplicates, it will just create the property, then overwrite it.
Here is the function:
function duplicateCheck() {
var output = document.getElementById('Output');
output.innerHTML = '';
var textArea = document.getElementById('Serials');
var inputSerials =
textArea.value.trim().split(/ *\n */);
var outputSerials = new Object();
for(var i = 0;i < inputSerials.length;i++){
var serial = inputSerials[i];
//build an object whose properties are serials
//if the serial exists, incremint a counter
if(outputSerials[serial]){
outputSerials[serial]++;
}else{
outputSerials[serial] = 1;
}
}
output.innerHTML =
'Serials: <br />';
for(var i in outputSerials){
output.innerHTML += i + " ";
}
output.innerHTML +=
'<br /><br />Duplicate Serials: <br />';
for(var i in outputSerials){
//check to see if we have any duplicates
if(outputSerials[i] > 1){
output.innerHTML += i + " ";
}
}
}
I think you'd get significantly better performance if you used an object to determine which serials you'd seen before. Something closer to this:
var seen = {};
for (var i = 0, j = serials.length; i < j; ++i) {
var serial = serials[i];
if (seen.hasOwnProperty(serial)) {
// Dupe code goes here.
continue;
}
// Can't be a duplicate if we get to this point.
}
Though that won't work with serials that use periods.
Here's a solution to filter out duplicates.
function formatInput() {
var arrUnique = [], dups = [],
str = document.getElementById('Serials').value
.replace(/\r\n?/g,'\n')
// normalize newlines - not sure what PC's
// return. Mac's are using \n's
.replace(/(^((?!\n)\s)+|((?!\n)\s)+$)/gm,'')
// trim each line
.replace(/^\n+|\n+$|\n+(?=\n(?!\n))/g,''),
// delete empty lines and trim the whole string
arr = str.length ? str.split(/\n/) : [];
// split each line, if any
for (var i = 0; i < arr.length; i++) {
if (arrUnique.indexOf(arr[i]) == -1)
arrUnique.push(arr[i]);
else dups.push(arr[i]);
}
//document.getElementById('Serials').value = arrUnique.join('\n');
console.log('serials:', arr);
console.log('unique:', arrUnique);
console.log('duplicates:', dups);
}

For loop speed performance in javascript

I went throught http://www.youtube.com/watch?v=mHtdZgou0qU speed up your javascript.
So i did this personal speed test:
var count = 50000000;
var testDummy;
// test 1
testDummy = 0;
var test1Start = new Date().getTime();
var i;
for (i=0;i<count;i++) {
testDummy++;
}
var test1End = new Date().getTime();
var test1Total = (test1End-test1Start);
// test 2
testDummy = 0;
var test2Start = new Date().getTime();
var i
for (i=count; i--;) {
testDummy++;
}
var test2End = new Date().getTime();
var test2Total = (test2End-test2Start);
debug(
"test1\n" +
"total: " + test1Total + "\n" +
"test2\n" +
"total: " + test2Total
);
I get not significant results, like sometimes they are even and sometimes not.
My question is, if i use for loop like this: "for(i=count;i--;)" is it really faster ?
Am i doing something wrong in my tests.
Thanks for your help!
(I'd write this as a comment, but it'd be too long.)
First: Worrying about the efficiency of a for loop is almost always a waste of (your own) time. What's inside of the loop usually has much more impact on performance than the details of how the loop is specified.
Second: What browser(s) did you test with? Different browsers will show different performance profiles; even different versions of the same browser will differ.
Third: It's not out of the question that the JavaScript engine optimized your loops out of the picture. A JavaScript compiler could simply look at the loop and decide to set testDummy to 50000000 and be done with it.
Fourth: If you really want to split hairs on performance, I'd try for(i=count; --i != 0;) as well as for(i=count;i--;). The former may save a machine instruction or two, because executing the subtraction (in the predecrement step) may automatically set a hardware flag indicating that the result was 0. That flag is potentially wasted when you're using the postdecrement operator, because it wouldn't be examined until the start of the next iteration. (The chances that you'd be able to notice the difference are slim to none.)
Well...
for( i=0 ; i < len ; i++ )
is practically the same as
for( i = len ; i-- ; )
Lets describe it:
case 1:
let i be 0
boolean expression
let i be i + 1
case 2:
let i be len
let i be i - 1
cast i to boolean (type coersion) and interpret it.
The difference should be minute and depends entirely on how efficient type coersion is compared to a normal boolean expression.
Incidentally, test this:]
var i = count;
while( i-- ) {}
There's nothing wrong with your tests.
The blocks that you are testing are very-near identical, meaning the difference in execution speeds are going to be trivial. In both examples, a variable (i) is set to a fixed value and looped until it reaches a fixed value (count). The only thing that differs is i++ and i--, which in terms of speed, I think are practically the same.
The thing you have to be careful of (not do) is calculate the "loop until" value inside the loop definition.
I have made some tests too, here are the results.
In many articles, books authors propose that "optimized" loops are faster.
It seems that modern browsers have some optimizations for "normal" loops.
Firefox 13.0.1
Normal Loop: 0.887
Opt1: 1.025
Opt2: 1.098
Opt3: 1.399
Chrome 19.0.1
Normal Loop: 3.349
Opt1: 3.12
Opt2: 3.109
Opt3: 3.095
IE8
Over 12sec...
Repeatedly crashed during tests.
<script type="text/javascript">
function p(p) { console.log(p); }
// function p(p) { document.write(p); }
var testFn = function(num, niz, fn) {
var start = new Date().getTime();
fn(num, niz);
var result = (new Date().getTime() - start) / 1000;
return result;
}
function normalLoop(num, niz) {
for (var i = 0; i < niz.length; i++) {
niz[i] = 'a' + i;
}
}
function opt1(num, niz) {
var len = niz.length;
for (var i = 0; i < len; i++) {
niz[i] = 'a' + i;
}
}
function opt2(num, niz) {
for (var i = niz.length; i--;) {
niz[i] = 'a' + i;
}
}
function opt3(num, niz) {
while(i--) {
niz[i] = 'a' + i;
}
}
var niz = [];
var num = 10000000;
for (var i = 0; i < num; i++) { niz.push(i); };
p('Normal Loop: ' + testFn(num, niz, normalLoop));
p('Opt1: ' + testFn(num, niz, opt1));
p('Opt2: ' + testFn(num, niz, opt2));
p('Opt3: ' + testFn(num, niz, opt3));
</script>

Categories

Resources