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;
}
}
Related
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.)
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) :)
First of all, I've had a look on all the 'sleep' questions lying around (such as What is the JavaScript version of sleep()?) but I didn't find an acceptable solution.
I would like to make a visual education tool for all sort of algorithms. In order to do so, I'm using javascript with jQuery to display the data and paint it up nicely. In order to start it up, I want to do a sorting sample, where an array is displayed, shuffled and then sorted in a visually pleasing way. So what I want to happen is that two cells get highlighted (easy), possibly swapped (easy), and then there's a small delay before the next pair is tested (hard).
I understand there isn't an explicit 'sleep' method in javascript. However, to restructure the code into using setTimeout would imply rewriting all my algorithms recursively, which is a huge hinder (although obviously not impossible).
As a sample problem, take a look at a bubble sort sample:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
sleep(1000);
}
}
exhibit_array(arr);
}
This can obviously rewritten recursively to work with setTimeout, but to do so on all the algorithms I have in mind would take a great deal of time. Am I missing something? Is there an 'easy' way to leave the implementations as they are and place sleeps at will?
EDIT:
I found two solutions: a pretty one, and a compatible one.
The pretty one only works on firefox, I'm afraid, and makes use of the wonderful yield semantics (There is some sample explanation here: https://developer.mozilla.org/en/New_in_JavaScript_1.7). This actually solves my problem perfectly, thus:
function bubble_sort(arr){
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
yield true;
}
}
yield false;
}
var bubble = bubble_sort(arr)
function gen(){
if(bubble.next()){
setTimeout(gen, 500);
}
else{
alert("Done!");
}
}
This works wonderfully for me, but does rely on the yield capability which currently is only supported on firefox. Notice that for this to work at all, you need to use <script type="text/javascript;version=1.7">. This however is perfect. It could have also worked for infinite algorithms, showing them toiling in vain if need be.
The second solution I found works as well, based on the answer below:
function bubble_sort(arr){
var q = new Array();
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
q[q.length] = [ [highlight, j-1 ], [highlight, j] ];
if(arr[j-1] > arr[j]){
swap(arr, j, j-1);
q[q.length] = [ [visible_swap, j, j-1] ];
}
}
}
return q;
}
function play(q, step){
if(q.length == 0)
return;
clear_highlights();
cmds = q.shift();
for(ind in cmds){
cmd = cmds[ind];
f = cmd.shift();
f.apply(null, cmd);
}
setTimeout(function(){ play(q, step); }, step);
}
This works as well. This is pretty bothersome syntactically, but definitely works well on all browsers.
After all this though, it seems there are javascript 'extensions' which implement sleep-like syntax, which is obviously better than all of the above.
Thanks for the help!
Recently I made a visualization of sub-palindrome finder algorithm, it used setTimeout and didn't require rewriting of the algorithm in recursive form.
See this example.
The general principle is to build up a stack of commands, for bubble sort that would be a stack of highlight and swap commands. Then you can have a function running each N milliseconds which takes a command from the stack and visualizes it.
commands = [
['highlight', 1, 5]
['swap', 1, 5]
['highlight', 3, 7]
...
];
setInterval(function() {
var cmd = commands.shift();
visualize(cmd);
}, 1300);
In my problem the finder algorithm was written in Python and was provided by the user, and I couldn't modify it. Fortunately Python allows to overload access and comparison operators and record each action the algorithm takes. RecString class. In JavaScript you can't do that, but that's not a problem in your case, because you can modify the original algorithm.
I can email you the JS source if you want, it was written in haste, but might be useful anyway.
Another idea - StratifiedJS. Here's a simple jsFiddle example:
<script src="http://code.onilabs.com/apollo/0.13/oni-apollo.js"></script>
<script type="text/sjs">
for (var i = 1; i < 4; i++) {
alert(i);
hold(1000);
}
</script>
I would work with setTimeout, I believe that is the closest you are going to get to a "sleep" equivalent on the client-side.
This answer doesn't solve the general case, but perhaps you can increment the interval for each instruction so that they run one second after each other.
function bubble_sort(arr){
var interval = 0; // increases with each loop
for(var i=0;i<arr.length;i++){
for(var j=1;j<arr.length;j++){
(function(i, j) {
setTimeout(function() {
highlight(j-1);
highlight(j);
if(arr[j-1] > arr[j]){
visible_swap(arr, j, j-1);
}
}, interval);
})(i, j);
interval += 1000;
}
}
exhibit_array(arr);
}
Thus, the first operation runs at once, the next runs after one second, the thrid after a total of two seconds, etc.
This solution provides the benefit of minimal code rewriting: just wrap your loop contents in a setTimeout (which is wrapped inside a closure with your loop variables) and add a line to increment interval after each loop iteration.
Using setTimeout() is not recursion.
You can work with a closure to keep track of state. The for loops, however, have to be changed into while for this to work:
function bubbleSort(arr) {
(function(i, j) { // <- this closes over i and j
function nextSortStep() {
while (i < arr.length) {
while (j < arr.length) {
highlight(j - 1);
highlight(j);
if (arr[j - 1] > arr[j]) {
visibleSwap(arr, j, j - 1);
}
j++;
return setTimeout(nextSortStep, 1000);
}
i++;
j = 1;
return setTimeout(nextSortStep, 1000);
}
exhibitArray(arr);
}
nextSortStep();
})(0, 1); // <- loop initialization
}
As an aside, JavaScript is not PHP, function names generally are in camelCase.
Following Lebedev's idea, I would store the "evolution of the sorting of the array" and then use setInterval() to show them.
http://jsfiddle.net/mari/EaYRZ/
Im working on a script which removes the default values in form elements using Prototype and LightView. The scripts works fine in Safari, but not at all in FireFox (3.5.5).
This fires when a lightview is triggered.
document.observe('lightview:opened', function() {
if($('contact_form')) {
var defaults = new Array();
var ins = $('contact_form').getElements();
var inlen = ins.length;
for(i=0; i < inlen; i++) {
alert(i)
if($(ins[i]).readAttribute('type') != 'image') {
defaults[ins[i].name] = $(ins[i]).value;
$(ins[i]).observe('focus', checkDefault.bind(event, ins[i]));
}
}
function checkDefault(name, event) {
alert(name.name)
if($(name).value == defaults[name.name]) {
alert(defaults[name.name])
$(name).value = '';
}
}
}
});
The strange this is, when I check for the length of inlen the proper number is alerted, but when I alert 'i', only the first number is alerted. I can't figure out why this is happening.
Any ideas what's wrong here?
Here is the address of the problem:
http://bearing.krd-design.net/
Thanks
Rich
I'm not sure if this would cause that problem, but you are missing var:
for(var i=0; i < inlen; i++) {
Also, there are no semi-colon's after any of your alert()s.
Try correcting those, and see if it makes a difference.
EDIT:
As pointed out by Matt, in the comments: neglecting var creates the variable in the global scope. This could cause a problem if prototypejs also uses a global variable i (but I sincerely doubt that).
EDIT 2:
Another possibility is the array accessing by input name:
defaults[ins[i].name] = $(ins[i]).value;
Try declaring defaults as an object:
var defaults = {};
It sounds like a timing issue; the alerts slow execution to the point where your code works in FF. Do you use FireBug?
First of all, I think it is only going to i=0 is probably because the JS broke during the first iteration. To troubleshoot, I'd put alert() in between lines and see which line is breaking it.
My guess of the problem should be in the line:
$(ins[i]).observe('focus', checkDefault.bind(event, ins[i]));
The first parameter of the 'bind' function should be context and you are passing in 'event'. 'event' isn't defined and it should be the context or scope.
In your case, I think you can just use:
$(ins[i]).observe('focus', checkDefault(ins[i]));