Not inserting element on call inserts after the entire execution - javascript

function loadval() {
r = Math.floor(Math.random() * load.length);
console.log(r);
for (let i = 0; i < 9; i++) {
for (let j = 0; j < 9; j++) {
var set = (i + 1) * 10 + j + 1;
var x = document.getElementById(set);
x.value = load[r][i][j];
console.log(load[r][i][j]);
sleep(25);
}
}
}
The element is not inserted one by one after the delay, all the elements are set after the whole function gets executed.

why not use setInterval or setTimeout instead sleep(25)?
// repeat at 2 second intervals
let timerId = setInterval (() => loadval(), 2000);
// stop output after 10 seconds
setTimeout (() => {clearInterval (timerId); alert ('stop');}, 10000);

Related

Cannot set innerHTML inside setTimeout

Trying to set the innerHTML of a HTML class which are four boxes, each to be set 3 seconds one after another. I can set the innerHTML without setTimeout when the innerHTML is set to a loading icon. When innerHTML is put inside setTimeout the following is returned: 'Uncaught TypeError: Cannot set property 'innerHTML' of undefined'.
Tried to debug my code sending messages to the console and searching stackoverflow but no luck.
var x = document.getElementsByClassName("numberBox");
for (var i = 0; i < 4; i++) {
x[i].innerHTML= '';
x[i].innerHTML= "<div class='loader'></div>"
}
// function to generate array of 4 random numbers
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
}
Would like to know why my innerHTML cannot be set within setTimeout here and possible solutions to my problem.
I believe this is a question of the current scope. The setTimeout function creates its own scope that has no reference to the old variable. You'll likely need to redefine what x is inside the timeout or pass the array explicitly to the timeout.
See here for how-to: How can I pass a parameter to a setTimeout() callback?
I would also recommend reading up on closers as well: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures
When you use var inside the for-loop the setTimeout is actually triggered for the last value of i as in var the binding happens only once.
This is because the setTimeout is triggered when the entire loop is completed, then your i will be 4. Keep in mind that there is a closure because of the callback function you pass in the setTimeout call. That closure will now refer to the final value of i which is 4.
So in this case when the complete loop has executed the value of i is 4 but there are indexes upto 3 in x. That is why when you try to access x[4] you get undefined and you see TypeError to fix this just use let for fresh re-binding with the new value of i in every iteration:
for (let i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
}
Also if you cannot use let due to browser incompatibility you can do the trick with a IIFE:
for (var i = 0; i < 4; i++) {
(function(i){
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
})(i);
}
This works because var has function scope, so here in every iteration a new scope would be created along with the function with a new binding to the new value of i.
Because of missing i parameter - timeout probably used last (4) which was out of array.
But you can set&use function parameters by adding next timeout parameters.
var x = document.getElementsByClassName("numberBox");
for (var i = 0; i < 4; i++) {
x[i].innerHTML= '';
x[i].innerHTML= "<div class='loader'></div>"
}
// function to generate array of 4 random numbers
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout(function (i) {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i, i);
}
function generateRandomNumbers() {
var retVal = [];
for (var i = 0; i < 4; i++) {
retVal.push(Math.random());
}
return retVal;
}
<div class="numberBox"></div>
<div class="numberBox"></div>
<div class="numberBox"></div>
<div class="numberBox"></div>
// function to generate array of 4 random numbers
var x = document.getElementsByClassName("numberBox");
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i, x);
}
This problem is related to a very basic and popular concept of Javascript called closure. It can be solved in at least two ways:
Using let
var x = document.getElementsByClassName("numberBox");
for (let j = 0; j < 4; j++) {
x[j].innerHTML= '';
x[j].innerHTML= "<div class='loader'></div>"
}
// function to generate array of 4 random numbers
var randomNums = generateRandomNumbers();
for (let i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
}
Using IIFE
var x = document.getElementsByClassName("numberBox");
for (var i = 0; i < 4; i++) {
x[i].innerHTML= '';
x[i].innerHTML= "<div class='loader'></div>"
}
// function to generate array of 4 random numbers
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout((function (j) {
x[j].innerHTML= '';
x[j].innerHTML = randomNums[j];
})(i), 3000 * i);
}
You are trying to access x in a inner method, that is x is not defined in the scope of setTimeout that is why you receive that execption
I would suggest you use a setInterval function as the solution
Your code:
var randomNums = generateRandomNumbers();
for (var i = 0; i < 4; i++) {
setTimeout(function () {
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
}, 3000 * i);
}
A work around
var randomNums = generateRandomNumbers();
let i = 0;
let interval = setInterval(function() {
if( i != 2){
x[i].innerHTML= '';
x[i].innerHTML = randomNums[i];
i += 1;
} else {
clearInterval(interval) ;
}
}, 3000);
This issue appears to be caused by several factors.
Defining the generateRandomNumbers() function outside the setTimeout() scope.
Using the var definition inside your for loop.
function generateRandomNumbers() {
return Math.floor(Math.random() * 999999) + 10000;
}
var x = document.getElementsByClassName("numberBox");
for (var i = 0; i < x.length; i++) {
x[i].innerHTML= '';
x[i].innerHTML= "<div class='loader'></div>"
}
for (let i = 0; i < x.length; i++) {
setTimeout(function() {
x[i].innerHTML= '';
x[i].innerHTML = generateRandomNumbers();
}, 3000 * i);
}
This is a different implementation, but here's a Fiddle

Calling clearInterval in Browser Console on Chrome

I am running this JS code in my Browser Console to display some names from a table in an interval of 4 seconds. After the loop has run X amount of times, it should clear the interval.
$(document).ready(function() {
for(var j = 0; j < 2; j++) {
var refreshIntervalId = setInterval(function(){var td = $("tr td:first-child");
for (var i = 6; i < 26; i++){
console.log(td[i].innerText);
}},4000);
$("#idc4").click();
}
clearInterval(refreshIntervalId);
});
I've saved the interval ID in the variable refreshIntervalId and I am calling the clearInterval function after the loop with this ID, but my interval keeps running, displaying the same names in the console. Is the variable out of scope? Or does the browser console have some limitations when it comes to this?
You need your intervals to stop themselves after they've been called X times.
So you'll need to change your code's logic a little. Because right now, your for loop combined with the use of var will replace your intervalId each time you loop.
I introduced an intervalContext object that contains the intervalId and the number of times it was called. By binding it to the interval, each interval has its own intervalContext.
// how many times will the interval be called :
var numberOfCalls = 3;
for (var j = 0; j < 2; j++) {
// initiating a new intervalContext
var intervalContext = {};
intervalContext.called = 0;
// storing the intervalId in the intervalContext so the interval can clear itself
intervalContext.intervalId = setInterval((function() {
// the intervalContext object will be referenced by 'this'
this.called++;
for (var i = 6; i < 26; i++) {
console.log("looping i = " + i);
}
if (this.called > numberOfCalls) {
console.log("Interval cleared. ID=", this.intervalId);
clearInterval(this.intervalId);
}
}).bind(intervalContext), 1000); // binding the interval to the intervalContext
console.log("Interval started. ID=" + intervalContext.intervalId);
}

Why is it faster to perform an assignment than do nothing?

class Obj {
constructor() {
this.propA = ~~(Math.random() * 255 + 0.5);
this.propB = ~~(Math.random() * 300 + 0.5);
}
}
const arr1 = new Array(100000);
for (var i = 0; i < 100000; i ++) {
arr1[i] = new Obj();
}
function test1() {
let start = new Date();
for (var times = 0; times < 1000; times ++) {
let n = 0;
for (var i = 0; i < 100000; i++) {
if (arr1[i].propA > arr1[i].propB) {
n += 1;
//arr1[i].propB = arr1[i].propA; //<-- try uncomment it
}
}
}
console.log(new Date() - start + 'ms');
}
test1();
paste this code to developer tools(or a new .html file).
on my computer(win7 x64, chrome 63) it prints 1200-1600ms.
however when I uncomment the code it prints only 500-700ms.
I don't know why it happens...
I don't know why it happens...
Because after firs time when
arr1[i].propB = arr1[i].propA;
has been executed, from the next iteration
if (arr1[i].propA > arr1[i].propB)
will be false and hence that line n += 1; will not get executed.
Since you are saving one operations by replacing increment and assignment with only assignment, you see a improvement in speed.

Javascript Loop Delay needed

I Need 3 second delay after 2nd loop. place is commented out. pleaes help.
var x = [[1,2,3,4,5,6,7],[8,9,10,11,12,13,14],[15,16,17,18,19,20,21],[22,23,24,25,26,27,28],[29,30,31,32,33,34,35],[36,37,38,39,40,41,42],[43,44,45,46,47,48,49]];
var j=indx='';
var n = 7;
var slice = j= indx='';
for (slice = 0; slice < 2 * n - 1; ++slice) {
var z = slice < n ? 0 : slice - n + 1;
for (j = z; j <= slice - z; ++j) {
indx = x[j][slice - j]-1;
console.log(indx);
}
//window.setTimeout("", 1000);
//i need delay here.----------------------
}
use setInterval(callback, time). It's the same as setTimeout but function will be called forever.
clearInterval should be called with your interval's id to stop execution.
setInterval function returns that id
var intervalId = setInterval(function(){
var z = slice < n ? 0 : slice - n + 1;
for (j = z; j <= slice - z; ++j) {
indx = x[j][slice - j]-1;
console.log(indx);
}
if(++slice >= 2*n-1)
clearInterval(intervalId);
}, 3000);

Can't call a function through setTimeout

I'm trying to make a few functions to work one after the other with a waiting time of 1.5 seconds between them.
NOW, when i try doing so with the same Id (Inside the "NoteList(>here<)", like 1, 2, 3, or any other, it works;
for (var i = 0; i < 36; i++)
{
setTimeout(function () { OnClcRandom(NoteList[0]) }, i * 1000 + 1000);
}
BUT! when i try doing so with the var i, it doesn't work and gets the all of the functions in the page stuck. any idea why?
for (var i = 0; i < 36; i++)
{
setTimeout(function () { OnClcRandom(NoteList[i]) }, i * 1000 + 1000);
}
That would be because all of the functions refer to the same live i variable, not the value of the variable at the time you called setTimeout(). Which means by the time the timeouts actually run your function i will be 36.
Try this instead:
for (var i = 0; i < 36; i++) {
(function(x){
setTimeout(function () { OnClcRandom(NoteList[x]) }, i * 1000 + 1000);
)(i);
}
This executes an anonymous function on each iteration of the loop, with each execution getting its own x parameter for use in your original function.
Javascript doesn't create local scope for block. :)
And in your second example var i equal 36 (last value).
You need create local scope inside loop.
for (var i = 0; i < 36; i++) {
(function (i) {
setTimeout(.......);
}(i))
}
You also may fixed 'i' value assign it to function property:
for (var i = 0, f; i < 36; i++){
f = function _callback() { var i = _callback.i; .....};
f.i = i;
setTimeout(f, i * 1000);
}

Categories