By using a for-loop to ask the server for several database entries I wrote a piece of code, which works proper good, BUT:
Magically this piece of code doesn´t work on the IE11.
For Google Chrome, Firefox, Safari, ..., it works porper good. But unfortunately I need to use IE11. The code doesn´t give an error, but the data returned from the server are not there. Just the last element in the for - loop got transmitted.
By using the IE Network connection representation tool, it can be seen that all requests got sent back, but somehow just the last one is already there. Mabye someone had already this problem and can give me some hints...
function getData(setAddress_Event, liter_hour, Fluid_id, dateArray){
return $.getJSON(setAddress_Event + liter_hour + Fluid_id + "/" + dateArray).then(function(data){
return {
data_list:data
};
});
}
//get day2day data
var numPendingResults = dateArray.length;
//new var declaration --> "let" is only valid inside the for loop!!
for(let j = 0; j<dateArray.length; j++)
{
getData(setAddress_Event(), "liter_hour/", Fluid_id, dateArray[j]).then(function(returndata){
//received data!
data_collection[j] = returndata;
numPendingResults--; // one less to wait for!
if (!numPendingResults) { // we have everything!
//console.log(data_collection);
//function call which sends the data forward
dataReady(data_collection, data_limit);
}
the function dataReady, should process the received data, but somehow using IE11, just the last request from the loop is there! Therefor I decided to open a new QUESTION. Maybe there is one genius who can give me some hints...
It's an incompatibility in IE11 with the specification.1 Unfortunately, let in for loops is incorrectly implemented in IE9-IE11 (and Edge up to and including Edge 13; Edge 14 finally gets it right). In a browser compatible with the ES2015 (aka "ES6") specification, this code should show 1, 2, 3, 4, 5; but on IE11, it shows 6, 6, 6, 6, 6 instead (like it would if we used var).
for (let i = 1; i <= 5; ++i) {
setTimeout(function() {
console.log(i);
}, 0);
}
You have a couple of options:
Use one of the other solutions for dealing with closures in loops instead of the let solution.
Use let, but inside the loop
Here's #2, which works correctly on IE11:
for (let i = 1; i <= 5; ++i) {
let inner = i; // Different variable
setTimeout(function() {
console.log(inner);
}, 0);
}
1 Originally I called it a "bug," but it's worth noting that IE11 was released two years prior to the final ES2015 specification, and the exact semantics for let in loops moved around during the specification process, so it could just be that Microsoft jumped the gun and implemented what they thought it was going to be based on current conversations, only to have it change before the final spec came out. It's the danger of implementing too early in the specification process. (That process has, itself, been formalized more in the meantime, to help vendors avoid this kind of thing.)
Related
I have a piece of JS code which parses through a file, then associated the array with a key-value pair map, and then iterates it through it to find the proper city name with a .includes method. My problem is that the final field (where the function in question is called) works fine on my end for both Chrome and Firefox. It does not work for some reason for my group members.
This is the JS snippet that does the iterating:
Edit: this is how the file is being opened:
var rawFile = new XMLHttpRequest();
rawFile.open("GET", "../data/myFile.txt", false);
for (var i = 0; i < allText.length; i++) {
if (i % 2 == 0) {
myMap[allText[i]] = allText[i + 1];
}
}
var city = document.getElementById("city").value;
for (var key in myMap) {
if (myMap.hasOwnProperty(key)) {
if (myMap[key].toLowerCase().includes(city.toLowerCase())) {
document.getElementById("city").value = myMap[key]
document.getElementById("zipcode").value = key;
}
}
}
This is the html part that calls it:
<label for="myLabel">City: </label>
<input type="text" name="myLabel" id="myLabel" onblur="readTextFile()">
What exactly is the problem and how can I troubleshoot it as it makes no sense to me, coming from the world of Java and C++, where I have never faced such an issue before. If you are wondering why the JS might be kinda ugly, it is the result of a student with a teacher who thinks that showing W3Schools examples is equivalent to good teaching.
Javascript includes function may work erratically due to some browsers not supporting it. You need to be wise while choosing the javascript functions specially when mozilla may have some functions which are not supported on some browsers. W3schools also provides a list of Browser support for a function. Check the link below for that list for includes function:
http://www.w3schools.com/jsref/jsref_includes.asp
Alternatively, you can use indexOf function like:
myMap[key].toLowerCase().indexOf(city.toLowerCase()) >= 0
I have myself faced issues with includes function hence providing you a workaround. Happy programming.
I'm looping through a dataset with a couple of thousand items in it like this.
users.forEach(function(user){
//List ALLTHETHINGS!
listAllEverything(user)
//Add gropings
user.groupings = groupings.filter(function(grouping){
return grouping.conditional(user)
})
//Add conversions to user, one per user.
user.conversions = {}
//for each conversionList
conversionLists.forEach(function(conversionList){
user.conversions[conversionList.name] = [];
//for each conversion
for (var i = conversionList.conversions.length - 1; i >= 0; i--) {
var conversion = conversionList.conversions[i]
//test against each users apilog
var converted = user.apilog.some(function(event){
return conversion.conditional(event);
})
if (converted){
//Lägg till konverteringen och alla konverteringar som kommer innan.
for (var i = i; i >= 0; i--){
user.conversions[conversionList.name].push(conversionList.conversions[i])
}
break;
}
};
})
})
I know this is not the most optimized code and I have some ideas how it can be improved. But i'm pretty new to these kinds of problems, so I'm not sure how I should prioritize. I know about console.time, which is useful but I want to use something that allows me to compound the time spent on each part of the forEach-loop, either a tool (I usually use chrome) or some debugging-method. Perferably something that doesn't effect the performance too much.
Since you are using Chrome you shoud check out the Timeline tab in your browsers DevTools - just hit the record button before running the loop and stop it once it's done. You will se a nice breakdown of everything that just happened and you will be mostly interested in yellow bars - they show JavaScript operations.
Please check out this video presentation by Paul Irish about Performance Tooling
As you know, in Chrome or Firefox you can just wrap a piece of code with console.time (and console.timeEnd) and it will measure the speed of particular operation and print it in the console.
For example: to measure the time it takes for an entire loop to execute use:
console.time('For loop benchmark');
for(i=0; i<1000; i++) {
// do some operations here
}
console.timeEnd('For loop benchmark');
But, if you want to measure each iteration you can parameterize the name of the log inside the loop so that you can name each specific operation the way you want:
for(i=0; i<1000; i++)
var consoleTimeName = 'Measuring iteration no '+i+' which is doing this and that...';
console.time(consoleTimeName);
// do some operations here
console.timeEnd(consoleTimeName);
}
Using it you can see for yourself how much faster simple for loop can be in comparsion to jQuery's $.each loop.
You can find more about this on developer.mozilla.org and developer.chrome.com. Please not that this is note a standarized, cross-browser compatibile feature and you should not be using it on a production website, since some browser like IE may throw you an error when they see it.
Update: This bug affects v28 and was fixed for v29 onward.
Having a function like this:
function arrMany(len) {
var a = new Array(len);
}
If the function is called rapidly the length of the produced array sometimes has length of previous call to the function.
Expanding the function to:
function arrMany(len, show) {
var a = new Array(len);
if (show) {
someElementTextA.value = a.length;
someElementTextB.value = len;
}
}
And calling by e.g.:
function tick() {
arrMany(2);
arrMany(4);
arrMany(6);
arrMany(10, true);
}
setInerval(tick, 1000 / 200);
after a while someElementTextA shows the value 6 and not 10.
Sample fiddle edit
Sample fiddle show
When this happens, and one turn down fps to for example 1, it keeps spitting out wrong length for a long time.
The behavior typically manifests itself after about 20 seconds on my system.
Tested on: Firefox Linux i686; rv:28.0
Notes:
No action in Browser Console or Web Console.
If Web Console is open the error never occurs.
If Web Console is opened when the error manifests, it corrects itself at once.
Given pt. 3. it is rather hard to debug in a sane way using the browser itself.
Any good fix to this?
Update 1:
Have tested this on Firefox, Chrome and Opera. Firefox is the only browser that manifests the bug. No action in console.
From comments and answer: Does not manifest on Window XP, Firefox v31. Does manifest on #jdigital's system – i.e. it's not local to my system.
Update 2:
Always specifying show in above code does not make any difference.
function tick() {
arrMany(2, false);
arrMany(4, false);
arrMany(6, false);
arrMany(10, true);
}
Nor does using default parameter. But another point being that show is only for the convenience of the sample code.
As to solution for conundrum saying:
if (arr.length !== len) { arr = new Array(len); }
seems to work. But not sure if is is a fix, or if this can break the same way. Using
if (arr.length !== len) { arr = new Array(len); retry = 1; }
show that retry is done quite frequent.
Another fix, (as in debug testing); but in another way. By adding this inside the function, the array is always of correct length. As in: retry is always 0.
for (retry = 0; arr.length !== len && retry < 10; ++retry) {
arr = new Array(len);
}
As to question.
Question is more if there is any good fix to the bug, not if it is a bug or not.
Any information for why this is happening and if there is any similar code, e.g. not handling Arrays, that can break in the same way is also interesting, but was not part of the original question as such.
Update 3:
For, "what I am trying to do", it is a question about it in the general sense, not specific to a case.
It is not a syntax I usually use, but happens from time to time, usually in some debug or verbose output where using a sparse array is simpler then a loop. But it is then nice to know that it is not reliable.
At the same time I recognize others might have different needs and as such solutions to it, in the broad general sense, is always nice to have.
Then again; tipping it the other way around I guess it would be another argument against ever using it ... ;)
This worked for me:
function arrMany(w, show) {
(function () {
var a = new Array(w);
if (show) {
arw1.value = a.length;
arw2.value = w;
}
})();
}
Interesting read: JavaScript's Strange Threaded Nature
This code explores the following property:
(function() { new Object(); })(); is garbage collected properly
It looks like a bug in Firefox. This problem does not occur in Chrome etc.
When I add a logging statement:
function arrMany(w, show) {
var a = new Array(w);
if (show) {
if( a.length != w ) {
console.log(a);
}
arw1.value = a.length;
arw2.value = w;
}
}
When I run this, I can see that console.log is occasionally triggered, and the Firefox Web Console window shows that the array has 5 elements.
If I understand correctly, you want a workaround for this bug, even if it is an ugly hack, as long as it is reliable. If so, consider this approach, which explicitly initializes the array:
function arrMany(w, show) {
// should be:
// var a = new Array(w);
// but there's a bug in Firefox, see StackOverflow 22726716
//
var a = [];
for( var i = 0; i < w; i++ ) a[i] = undefined;
if (show) {
arw1.value = a.length;
arw2.value = w;
}
}
Edit
After spending several hours on this and working with #pst, it turns out the issue was completely different.
Inside the code, you can see I used a timestamp shortcut of "+new Date()". This returns a timestamp as does the standard "new Date().getTime()".
However, +new Date() performs very, very badly when used with mathematical operations (+,-,/). Although the typeof() for the 'start' variable says 'number', something happens that makes it bloody slow. When using the standard getTime() method, there is no performance penalty when doing the timing subtractions.
Take a look at this jsperf detailing the problem, http://jsperf.com/new-date-timing.
In regards to #pst's very detailed answer and the efforts I made to replicate the linked question, use his answer as the canonical answer to that question.
I am going to change the title of this question to accurately reflect #pst's answer and my original intent, but will leave the original title and question for future reference.
New Question
Do javascript arrays utilize branch prediction on arrays of random sorted and unsorted data?
See #pst's answer below.
Original Title and Question below
Title: Array iterations taking 2x as long on the same data
I was looking at this question earlier, Why is it faster to process a sorted array than an unsorted array?, and wanted to try setting up the same test in javascript.
This has lead me to something unexpected. In the tests linked in the following fiddle, simply iterating over the same array of randomly generated number values with the same code results in vastly different response times.
I've tested this in Chrome, Safari, Firefox, and node.js.
In Chrome & node, the first iteration is faster than the 2nd iteration. In Safari and Firefox, the first iteration is slower than the 2nd iteration.
Here's the fiddle, http://jsfiddle.net/9QbWB/6/
In the linked fiddle, I've disabled sorting (thinking that was originally the issue, but it wasn't). Sorting the data made the looping even longer.
I've gone through the code pretty thoroughly to make sure I've removed anything that could be affecting the results. I feel like a particular set of scientists announcing FTL neutrinos, where I can't find a problem in my experiment and the data is unexpected.
In the code I'm including below, a few things like initial setTimeout, jQuery DOM visualizations, etc are for displaying data visually in jsfiddle.net. The core functions are the same.
//javascript test of https://stackoverflow.com/questions/11227809/why-is-processing-a-sorted-array-faster-than-an-unsorted-array
setTimeout(function(){
var unsorted_list = $('#unsorted'),
sorted_list = $('#sorted');
var length = 32768,
data = [];
for(var i=0; i<length; i++){
data[i] = Math.floor( Math.random()*256);
}
var test = function(){
var sum = 0,
start = +new Date();
for(var i=0; i<1000; i++){
for(var c=0; c<length; c++){
if( data[c] >= 128 ){
//sum += data[c];
}
}
}
return +new Date() - start;
}
//Unsorted
var results = 0;
for( var i=0; i<10; i++){
var x = test();
console.log(x);
unsorted_list.append('<div>'+x+'</div>');
results += x;
}
unsorted_list.append('<div>Final:'+(results/10)+'</div>');
console.log( 'Unsorted: ', results/10 );
//Sort array
//data.sort();
//Sorted
var results = 0;
for( var i=0; i<10; i++){
var x = test();
console.log(x);
sorted_list.append('<div>'+x+'</div>');
results += x;
}
sorted_list.append('<div>Final:'+(results/10)+'</div>');
console.log( 'Sorted: ', results/10 );
},5000);
(Apparently this answer misses the question - left here for related reasons.)
Here is my jsperf case - http://jsperf.com/sorted-loop/2 - perhaps enough something will be revealed with more browsers. I have also included a test case using only bit-wise operations, as taken from the linked post (and I have not verified the validity in JS).
CONCLUSION: the performance appears to be related to branch prediction.
The "+bitwise" test pair that does not use a condition are equivalent in speed (for the same browser) across all major browser runs. (Chrome is just faster than FF which just faster than IE at bit-wise operations; see other SO posts.)
The "+cond" test pair that uses the condition is greatly affected and the sorted data is highly favored. This is the result that would be expected if branch prediction is a factor.
I am currently building a small web application with similar functionality across all modules. I want to code small generic functions so that all programmers next to me, call these functions and these functions return necessary but important data for them to implement their functionality. In this example, I am trying to deal with the typical "choose true or false" exercise. So from the template.php they call this function:
function checkAnswers(){
var radiobuttons = document.form1.exer1;
var correctAnswers = answers(); //this is an array of string
var checkedAnswers = checkExerciseRB(radiobuttons, 2, correctAnswers);
for(i=0; i<checkedAnswers.length; i++){
alert(checkedAnswers[i]);
}
}
Function checkExerciseRB is my generic function, it is called from checkAnswers.
function checkExerciseRB(rbuttons, opciones, correct){
var answers = new Array();
var control = 0;
for(i=0; i<rbuttons.length; i++){
var noPick="true";
for(j=0; j<opciones; j++){
if(rbuttons[control+j].checked){
if(rbuttons[control+j].value==correct[i]){
answers[i]= 1;
noPick="false";
break;
}
else{
answers[i]=2;
noPick="false";
break;
}
}
}
if(noPick=="true")
answers[i]=0;
control=control+opciones;
}
return answers;
}
It works great but while looking at my favorite browsers (FireFox, Chrome) error log it says:
TypeError: rbuttons[control + j] is undefined
Any clue on how to deal with this matter?
This probably means that control + j is greater than or equal to the length of the array rbuttons. There's no such array element as rbuttons[control + j].
You should learn how to use the JavaScript debugger in your favorite browsers! Debuggers are great. They let you watch this code run, line by line, as fast or as slow as you want, and watch how the value of control changes as you go.
You’ll watch it, and you’ll think “Oh! That line of code is wrong!”
You're looping through rbuttons.length times, but in each loop you're adding 2 to control. Using control to index your array, you're going to run past the end.
Does the index specified by control + j exist in the array? i.e: If that evaluates to 4, is there at least 5 items in the array?
Also, you should be using var i, var j, etc inside your for loop. Without it your variables are leaking into the scope this code is executed in (most likely the global scope, and that's not good) :)