I wanna use Chrome or Firefox Developer Tools to execute code on a website.
When I execute a "window.RR" variable lonely, it shows me the right value (it is a measure of the site's server time (in milliseconds) and every time I execute it gives me a different value). When I use it in a loop (variable c), then the variable is constant in all loops and it equals to the value of the first loop.
My code is:
var i;
b=window.RR;
for (i=0 ; i<400000 ; i++) {
c=window.RR;
if (c!==b) {
alert(c)
}
}
I expect to receive the correct value when I use it in the loop, how can I achieve this?
I assume the the window.RR variable is updated by an interval. This means that the variable is updated asynchronous.
For example, lets say that the window.RR holds the timestamp (in milliseconds) of the server, and the code below updates the window.RR every millisecond.
setInterval(function () {
window.RR += 1;
}, 1);
If you then run a loop, that may take more than 1ms to be executed
var c = window.RR;
for (var i = 0; i < 999999999999999; i++){
if (c != window.RR) { // This is always false
console.log('This will never be printed');
}
}
the window.RR will not change during the execution of the loop, because the javascript asynchronous codes does not run in parallel.
Thus, if the loop takes more than 1 ms to be executed window.RR update code will happen after the loop finish (it will have to wait any other code fired to finish before that code can be executed).
More info:
This code does not let any other code to run while the for loop is running.
var c = window.RR;
for (var i = 0; i < 999999999999999; i++){
if (c != window.RR) { // This is always false
console.log('This will never be printed');
}
}
In order to let other code to run, you will have to make each loop async.
var c = window.RR;
var loop = function(i) {
if (i < 999999999999999) {
i++;
if (c != window.RR) {
console.log('This will be printed!');
}
else {
// Allow other javascript codes to run
// So that the window.RR can be updated
setTimeout(function () {loop(i);}, 0);
}
}
};
loop(0);
Related
for(let i = 0; i< 3; i++){
setTimeout(function (){
console.log(i)
}, 200);
}
The above code first returns a random number each time I run it in the console before returning 0 1 2.
Why does it happen like that?
When you post that code to the console in the developer tools on the browser, it evaluates it and outputs whatever it returns. And setTimeout returns the timeout id, which can be used to abort it with clearTimeout for example. Of course, the code also runs, and executes as expected, which results in the other outputs.
It's not the for loop that's returning a value. It's setTimeout.
When you write setTimeout it returns a Number, representing the ID value of the timer that is set. You can use this value with the clearTimeout() method to cancel the timer
let timer = setTimeout(function () {
console.log("Here")
}, 200)
clearTimeout(timer)
In your example, if you add the return value to the array you can see all the ids
let timers = []
for (let i = 0; i < 3; i++) {
timers.push(setTimeout(function () {
console.log("Here", i)
}, 200))
}
console.log(timers)
I'm trying to run an asynchronous for loop, which runs a synchronous function and then waits for a period of time. My code is :
function loopExec (i,imax, execFunc,param1) {
execFunc(i,param1);//Launch synchronous function which takes some time
var y=i+1;
if (y < imax) { // if the counter < imax, call the loop function
setTimeout(function () { // call a 0.1s setTimeout when the loop is called
loopExec(y,imax, execFunc,param1); // .. again which will trigger another call
}, 100);
}
else if(y==imax){
anotherFunction(param1);// The loop is over, clean up and log
}
}
The behaviour that I want is :
execFunc(1) -> wait 100ms -> execFunc2-> wait...
A bit like this
The behaviour that I have is execFunc1, execFunc2, etc all launching at 100 ms interval, without waiting for completion of the previous one, resulting in a read/write conflict as these functions interact with files.
I don't know if this has anything to do with it, but I'm using electron/nodeJS.
T.J. Crowder was right, the error is not in this function, but in the function it was calling.
This code does what is expected.
If you want to do something like this
this code will works.
var i = 0;
var imax = 10;
function myFunction() {
console.log('balbla', i);
i+=1;
if(i !== imax) setTimeout(myFunction, 100);
}
setTimeout(myFunction, 100);
I have a small JavaScript code in which I'm trying to use setTimeout to either wait for some external input to arrive (via responseReceived variable), OR wait for a max threshold time and then quit.
Here's the code:
var MAX_WAIT_THRESHOLD = 5000;
var keepWaiting = true;
var waitInterval = 500;
var totalTimeWaited = 0;
alert("Alert1");
while(keepWaiting == true) {
setTimeout(function() {
totalTimeWaited = totalTimeWaited + waitInterval;
alert("Alert2");
if(responseReceived == true || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
keepWaiting = false;
}
}, waitInterval);
}
The problem is for some reason setTimeout(..) never actually calls the anonymous function created inside it. I checked this by placing breakpoints in Chrome's JavaScript execution control, and execution never actually stops at any breakpoint placed inside the anonymous function. JavaScript's execution keeps toggling between the while .. line and setTimout(..) line. responseReceived is set elsewhere in the code. Another way of saying this is that the first alert shows (Alert1) but the second one never shows (Alert2).
What am I doing wrong ?
EDIT:
I went through the 'duplicate' question reported but I fail to see how that is relevant to my question. My question is not regarding the while loop. Rather it's about why the internal anonymous function isn't being called.
Your code killed my browser tab. :D
Why don’t you just use setInterval and get rid of the while loop?
var MAX_WAIT_THRESHOLD = 5000;
var waitInterval = 500;
var totalTimeWaited = 0;
var waiting = true;
alert("Alert1");
var interval = setInterval(function() {
totalTimeWaited += waitInterval;
alert("Alert2");
if (responseReceived || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
// stop waiting
clearInterval(interval);
waiting = false;
alert("Done");
}
}, waitInterval);
This issue is related with the javascript concurrency model.
As far as I know, all your setTimeout callbacks can only be executed after the while loop ends, because that while loop is a message blocking the queue. But in this case, it never ends.There was another SO thread explaining this, but I can't find it now.
I see you're actually controlling the max time of the loop with control variables. However, since this control code is inside a setTimeout callback, it will not be pushed into the queue until the loops end, so the control var keepWaiting will never turn to false inside the loop. Should you take that control code outside the setTimeout function, it wouldn't break the browser and will at some point show the 'alert2' message -several times, in fact-:
var MAX_WAIT_THRESHOLD = 5000;
var keepWaiting = true;
var waitInterval = 500;
var totalTimeWaited = 0;
var responseReceived = false;
console.log("Alert1");
while(keepWaiting == true) {
setTimeout(function() {
console.log("Alert2");
}, waitInterval);
totalTimeWaited = totalTimeWaited + waitInterval;
if(responseReceived == true || totalTimeWaited >= MAX_WAIT_THRESHOLD) {
keepWaiting = false;
}
}
However, all the callbacks will fire at the end for the reasons exposed before.
If you want an eternal loop of setTimeouts, use recursion instead of iteration.
I have a long running function. Which iterates through a large array and performs a function within each loop.
longFunction : function(){
var self = this;
var data = self.data;
for(var i=0; len = data.length; i<len; i++){
self.smallFunction(i);
}
},
smallFunction : function(index){
// Do Stuff!
}
For the most part this is fine but when I am dealing with arrays above around 1500 or so we get to the point of recieving a javascript execution alert message.
So I need to break this up. My first attempt is like so:
longFunction : function(index){
var self = this;
var data = self.data;
self.smallFunction(index);
if(data.slides[index+1){
setTimeout(function(){
self.longFunction(index+1);
},0);
}
else {
//WORK FINISHED
}
},
smallFunction : function(index){
// Do Stuff!
}
So here I am removing the loop and introducing a self calling function which increases its index each iteration. To return control to the main UI thread in order to prevent the javascript execution warning method I have added a setTimeout to allow it time to update after each iteration. The problem is that with this method getting the actual work done takes quite literally 10 times longer. What appears to be happening is although the setTimeout is set to 0, it is actually waiting more like 10ms. which on large arrays builds up very quickly. Removing the setTimeout and letting longFunction call itself gives performance comparable to the original loop method.
I need another solution, one which has comparable performance to the loop but which does not cause a javascript execution warning. Unfortunately webWorkers cannot be used in this instance.
It is important to note that I do not need a fully responsive UI during this process. Just enough to update a progress bar every few seconds.
Would breaking it up into chunks of loops be an option? I.e. perform 500 iterations at a time, stop, timeout, update progress bar, perform next 500 etc.. etc..
Is there anything better?
ANSWER:
The only solution seems to be chunking the work.
By adding the following to my self calling function I am allowing the UI to update every 250 iterations:
longFunction : function(index){
var self = this;
var data = self.data;
self.smallFunction(index);
var nextindex = i+1;
if(data.slides[nextindex){
if(nextindex % 250 === 0){
setTimeout(function(){
self.longFunction(nextindex);
},0);
}
else {
self.longFunction(nextindex);
}
}
else {
//WORK FINISHED
}
},
smallFunction : function(index){
// Do Stuff!
}
All I am doing here is checking if the next index is divisble by 250, if it is then we use a timeout to allow the main UI thread to update. If not we call it again directly. Problem solved!
Actually 1500 timeouts is nothing, so you can simply do this:
var i1 = 0
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(i1++) }, 0)
System will queue the timeout events for you and they will be called immediately one after another. And if users click anything during execution, they will not notice any lag. And no "script is running too long" thing.
From my experiments V8 can create 500,000 timeouts per second.
UPDATE
If you need i1 passed in order to your worker function, just pass an object with it, and increment the counter inside of your function.
function doSomething(obj) {
obj.count++
...put actual code here
}
var obj = {count: 0}
for (var i = 0; i < 1500; i++) setTimeout(function() { doSomething(obj) }, 0)
Under Node.js you can aslo use setImmediate(...).
Here's some batching code modified from an earlier answer I had written:
var n = 0,
max = data.length;
batch = 100;
(function nextBatch() {
for (var i = 0; i < batch && n < max; ++i, ++n) {
myFunc(n);
}
if (n < max) {
setTimeout(nextBatch, 0);
}
})();
You might want to use requestAnimationFrame to break up your execution. Here is an example from an developers.google.com article Optimize JavaScript Execution where they even do a couple iterations a time if the task were quicker than X ms.
var taskList = breakBigTaskIntoMicroTasks(monsterTaskList);
requestAnimationFrame(processTaskList);
function processTaskList(taskStartTime) {
var taskFinishTime;
do {
// Assume the next task is pushed onto a stack.
var nextTask = taskList.pop();
// Process nextTask.
processTask(nextTask);
// Go again if there’s enough time to do the next task.
taskFinishTime = window.performance.now();
} while (taskFinishTime - taskStartTime < 3);
if (taskList.length > 0)
requestAnimationFrame(processTaskList);
}
Is there anything better?
If you’re OK with it working only in modern browsers – then you should look into “Web Workers”, that let you execute JS in the background.
https://developer.mozilla.org/en-US/docs/DOM/Using_web_workers
I have a very simple test page that tests jquery (1.4.2) queue and delay.
for (var i = 1; i <= 5; i++) {
$('#test')
//.delay(50)
.queue(function(next) {
console.log(i);
next();
});
}
Now when I run this code in FF with firebug, I get what I expected, 1 ~ 5.
However, if I un-comment delay, I got 6 five times instead?
Can someone please help me clarify this?
The i is a single variable stored one time and shared by all iterations of the loop. Without the .delay() you're using the value of i right then, so it's what you expect. With the .delay() however, you're using what the value is later...and later it's what it ended up as at the end of the loop, 6.
#Nick provides an excellent explanation for why it behaves like this.
For completeness, you can "fix" this by capturing the current value of i in a new scope. JavaScript has only function scope, so you have to use a function to capture the value. E.g. you can use an immediate function:
for (var i = 1; i <= 5; i++) {
$('#test')
.delay(50)
.queue((function(index) {
return function(next) {
console.log(index);
next();
}
}(i))); // <- function gets called directly with `i` and the returned
// function is passed to queue.
}
DEMO
Well for the following code in firebug console on stackoverflow
for (var i = 1; i <= 5; i++) {
$('#custom-header')
//.delay(50)
.queue(function(next) {
console.log(i);
next();
});
}
On console, you get result
1
2
3
4
5
[div#custom-header]
And for code
for (var i = 1; i <= 5; i++) {
$('#custom-header')
.delay(50)
.queue(function(next) {
console.log(i);
next();
});
}
You get result
[div#custom-header]
6
6
6
6
6
[Explanation]:
From this we can conclude that dealay(50) delays the the evaluation of the function inside queue so [div#custom-header] is printed first and i is printed which is all 6 (by the moment) because the loop (which is not delayed) is evaluated first (only the printing function inside queue is delayed).