I am trying to do a infinite loop, but it only works if I include an 'alert' on it. My code looks like this:
while( tocontinue ){
// Some code
alert('Accept to continue');
}
On this way, the user has to click to hide the alerts (for example, on Chrome), and then the loop continues correctly by itself. I need to implement this without any alert. I also tried this:
while( tocontinue ){
// Some code
tocontinue = false;
setTimeout(function(){tocontinue=true},500);
}
And with "window.setTimeout" too, and without the word "function(){}", but it doesn't work. I tried everything: some implementations on JavaScript of a sleep() function, calling the function each X time with setInterval, answers 1 and 3 on this post... :/
Thank you very much for your time.
I'm trying to implement a genetic algorithm, and I want to stop it when I decide (with a button that puts the global variable "tocontinue" to false). Meanwhile, I want a infinite loop.
Well, you won't be able to combine a true infinite loop with user interaction as they'll both be dependent on the same thread being able to work on them exclusively. But, you can get close with a near-instant interval.
var interval = setInterval(function () {
// some code
}, 10);
Possibly grouping a few iterations together for each round:
var interval = setInterval(function () {
var limit = 5;
while (limit--) {
// some code
}
}, 10);
But, the interval will keep the iteration going as quickly as possible while still giving some idle time for user interactions, like clicking a particular button to clear the interval.
document.getElementById('stopButton').addEventListener('click', function () {
clearInterval(interval);
}, false);
Example: http://jsfiddle.net/coiscir/xZBTF/
setInterval() may be more useful here.
function updateLoop() {
//All the code goes here
}
setInterval(updateLoop,500);
var reader = new XMLHttpRequest() || new ActiveXObject('MSXML2.XMLHTTP');
function loadFile() {
reader.open('get', 'ccc.txt', true);
reader.onreadystatechange = displayContents;
reader.send(null);
}
function displayContents() {
if(reader.readyState==4) {
var el = document.getElementById('main');
el.innerHTML = reader.responseText;
var data = el.innerHTML;
}
}
for(var I = 7; I >1; i+=3);
console.log(i)
Related
I have succeeded in cobbling together pieces of code that achieve my goal. However, I would like some advice from more advanced vanilla JS programmers on how I can go about reaching my goal in a better way.
To start, I want to introduce my problem. I have a piece of text on my website where a portion is designed to change every so often. For this, I am running through a loop of phrases. To run this loop continuously, I first call the loop, then I call it again with setInterval timed to start when the initial loop ends. Here is the code I've got, which works even if it isn't what could be considered quality code:
function loop(){
for (let i = 0; i < header_phrases.length; i++){
(function (i) {
setTimeout(function(){
header_txt.textContent = header_phrases[i];
}, 3000 * i);
})(i);
};
}
loop();
setInterval(loop, 21000);
Is there a better way to right this code for both performance and quality? Do I need to use async? If so, any material I can see to learn more? Thanks!
You can implement the same logic using recursion.
function recursify(phrases, index = 0) {
header_txt.textContent = phrases[index];
setTimeout(function () {
recursify(phrases, index < phrases.length - 1 ? index + 1 : 0);
}, 300)
}
recursify(header_phrases);
The function 'recursify' will call itself after 300 miliseconds, but everytime this function gets called, the value of index will be different.
If I understand your requirement correctly, you want top populate an element from an array of values.
A simple way to do this is:
doLoop();
function doLoop() {
var phraseNo=0;
setTimeout(next,21000);
next();
function next() {
header_txt.textContent = header_phrases[phraseNo++];
if(phraseNo>=header_phrases.length) phraseNo=0;
}
}
This simply puts the next() function on the queue and waits.
The call to next() before the function simply starts it off without waiting for the timeout.
this is assuming that header_txt and header_phrases are not global vars. using global vars isn't a good idea.
var repeatIn = 3000;
phraseUpdater();
function phraseUpdater() {
var updateCount = 0,
phrasesCount = header_phrases.length;
setHeader();
setTimeout(setHeader, repeatIn);
function setHeader() {
header_txt.textContent = header_phrases[updateCount++ % phrasesCount] || '';
}
}
I know my problem I just not sure how to resolve it. I have a custom domain and in a function call a while loop executes. In that loop i wanted an animation to occur in order.
So the first problem is that javascript by its nature executes every line thus item 2 starts before item 1 completes. Now the effect is so short that it "appears" to happen to all elements at once but in the debugger it is just looping one at a time.
Now my typical resolution would be to use SetTimeout() but that is causing the browser to lock. Reading this post (Trying to delay/pause/slow a while loop in jQuery) it makes sense that the browser is getting into an endless loop.
So how can I get a pause between element1 and element2 events? I thought perhaps to add a callback function to my custom domain but not sure if that will work as desired besides not being sure how to do it.
In the head of the page and read the comments for anything else I may be doing wrong or could do better.
$(document).ready(function ()
{
//pause long enough for person to visually take in page before starting
setTimeout(function () { PageLoadAnimation.onReady(); }, 1000);
});
My custom domain:
var PageLoadAnimation =
{
onReady: function ()
{
//black everything out just to be sure
PageLoadAnimation.BlackOutElements();
//flash & show
PageLoadAnimation.FlashElement();
},
BlackOutElements: function ()
{
$('#ParentContainer').children().hide();
},
FlashElement: function ()
{
//get array of all elements and loop till all are visible
var elementArray = $('#ParentContainer').children();
var $els = $('#PartialsContainer').children();
while (elementArray.length)
{
var $el = elementArray.eq(Math.floor(Math.random() * elementArray.length));
//if I put set timeout here is causes the infinite loop
PageLoadAnimation.FlashBlast($el);
elementArray = elementArray.not($el);
//if I put by itself it no diff as the while loop continues regardless
//setTimeout(1500);
}
},
FlashBlast: function ($el)
{
//flash background
$el.fadeIn(200, function () { $el.fadeOut(200) });
}
}
I'm not sure if it isn't working or if I am doing something wrong so I created these fiddles:
Original Fiddle
With Johan Callbacks
Using is animating property
WARNING THIS ONE WILL HANG YOUR BROWSER!
I don't think I am checking the isAnimating property the way Johan had in mind??
ANSWER FOR THIS SITUATION. Hopefully it will help others.
setTimeout in a loop was really my problem...but not the only problem. I was the other problem(s).
Me first.
Fool that I am I was really causing my own complications with two things I was doing wrong.
First using jsfiddle my javascript would error due to syntax or some such thing but fiddle doesn't tell you that (to my knowledge) so my fiddle wouldn't run but I took it in pride as MY CODE IS FINE stupid javascript isn't working.
Second I was passing my function to setTimeout incorrectly. I was adding the function parens () and that is not correct either which would bring me back to issue one above.
WRONG: intervalTimer = setInterval(MyFunction(), 1500);
RIGHT: intervalTimer = setInterval(MyFunction, 1500);
As for the code I read here (http://javascript.info/tutorial/settimeout-setinterval) setting a timeout in a loop is bad. The loop will iterate rapidly and with the timeout one of the steps in the loop we get into a circular firing squad.
Here is my implementation:
I created a couple variables but didn't want them polluting the global scope so I created them within the custom domain. One to hold the array of elements the other the handle to the setInterval object.
var PageLoadAnimation =
{
elementArray: null,
intervalTimer: null,
....
}
In my onReady function (the one the page calls to kick things off) I set my domain array variable and set the interval saving the handle for use later. Note that the interval timer is how long I want between images flashes.
onReady: function ()
{
elementArray = $('#PartialsContainer').children();
//black everything out just to be sure
PageLoadAnimation.BlackOutElements();
//flash & show
intervalTimer = setInterval(PageLoadAnimation.FlashElement, 1500);
},
Now instead of looping through the array I am executing a function at certain intervals and just tracking how many elements are left in the array to be flashed. Once there are zero elements in the array I kill the interval execution.
FlashElement: function ()
{
if(elementArray.length > 0) //check how many elements left to be flashed
{
var $el = PageLoadAnimation.GrabElement(); //get random element
PageLoadAnimation.FlashBlast($el); //flash it
PageLoadAnimation.RemoveElement($el); //remove that element
}
else
{
//done clear timer
clearInterval(intervalTimer);
intervalTimer = null;
}
},
So the whole thing is:
var PageLoadAnimation =
{
elementArray: null,
intervalTimer: null,
onReady: function () {
elementArray = $('#PartialsContainer').children();
//black everything out just to be sure
PageLoadAnimation.BlackOutElements();
//flash & show
intervalTimer = setInterval(PageLoadAnimation.FlashElement, 1500);
//NOT this PageLoadAnimation.FlashElement()
},
BlackOutElements: function () {
$('#PartialsContainer').children().hide();
},
FlashElement: function ()
{
if(elementArray.length > 0)
{
var $el = PageLoadAnimation.GrabElement();
PageLoadAnimation.FlashBlast($el);
PageLoadAnimation.RemoveElement($el);
}
else
{
//done clear timer
clearInterval(intervalTimer);
intervalTimer = null;
}
},
GrabElement: function()
{
return elementArray.eq(Math.floor(Math.random() * elementArray.length));
},
RemoveElement: function($el)
{ elementArray = elementArray.not($el); },
FlashBlast: function ($el) {
//flash background
$el.fadeIn(100, function () { $el.fadeOut(100) });
}
}
Hope that help others understand the way to go about pausing execution in javascript.
A callback example that might help:
FlashBlast: function ($el, fadeInComplete, fadeOutComplete)
{
if(arguments.length === 3){
$el.fadeIn(200, function () {
fadeInComplete();
$el.fadeOut(200, fadeOutComplete);
});
}
}
Usage:
PageLoadAnimation.FlashBlast($el, function(){
//fadein complete
}, function(){
//fadeout complete
});
Another idea that might help:
isAnimating: false,
FlashBlast: function ($el)
{
var dfd = $.Deferred(),
that = this;
that.isAnimating = true;
$el.fadeIn(200, function () {
$el.fadeOut(200, function(){
dfd.resolve();
})
});
dfd.done(function(){
that.isAnimating = false;
});
}
Then make use of the private property isAnimating.
Finally, to know if an element is under an animation, you can use $el.is(':animated').
Hope this helps. Let me know if anything is unclear.
I am doing some long polling (ajax) and I am looping the following portion of code.. There is code being executed above and below. This code is part of an internal messaging system. A certain portion of the page wil blink when a message arrives. If the user checks the message, it will remove the dash_notify from the JSON response, which needs to turn off the blinking. See below:
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
timer = setInterval(blink, 10);
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
}
console.log("initiate_dash");
blinking($(x));
} else if (!data.dash_notify) {
console.log("good");
clearInterval(timer);
}
The following JSON response that gets sent to this code is:
{"current_date_time":"January 8, 2013 - 4:02 pm","dash_notify":"1"}
It understand the initial blink IF the above data gets passed. If the following gets passed:
{"current_date_time":"January 8, 2013 - 4:02 pm"}
Then it throws an error:
Uncaught ReferenceError: timer is not defined
I cannot figure out how to fix the "else" portion working properly. If the code is initiated when the full dash_notify:1 response is sent, it works perfect. The button will blink, then if the user checks the message, it will no longer send dash_notify:1 and the button stops blinking. But if the code is initiated when dash_notify:1 is NOT set, it doesn't know what to do with the ClearInterval.
Basically I need the else portion fixed.
I have tried using different typeOf === undefined snippets, but it doesn't work.
Any help is appreciated.
Thank you!
EDIT:
This is currently working.. Timer is now defined above the statement
if(data.dash_notify == '1'){
var x = '#dash_notif_blink';
console.log("initiate_dash");
blinking($(x));
}else if (typeof timer != "undefined" && timer) {
clearInterval(timer);
}
}
This is working, but sometimes it trys to kill the timer but it doesn't actually do it. This happens every so often.
Looks like it's not working because timer doesn't exist outside your inner blinking function. I'm making an assumption here that you don't have var timer; somewhere outside the blinking function, which is strongly likely given the error you're getting.
Why this is happening:
If I'm right, and you're not declaring timer anywhere else in your code, then var timer is being implicitly added to the beginning of the blinking function:
function blinking(x) {
var timer;
timer = setInterval(blink, 10);
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
}
That makes timer a local variable inside blinking. Since you never pass it out of the closure, it doesn't exist once you're outside that function. So either you need to pull timer into the outer context (option 1) or make it available from inside blinking (option 2).
What to do:
If you want access to timer outside of that closure, you'll have to do one of two things:
1: Declare timer outside of blinking:
var timer = null;
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
//etc...
2: Make it the return value of blinking:
var t;
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
var timer = setInterval(blink, 10); //note the var keyword for best practice
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
return timer;
}
console.log("initiate_dash");
t = blinking($(x));
} else if (!data.dash_notify) {
console.log("good");
clearInterval(t);
}
Either one of these will work, and is more or less the same in terms of polluting the outer namespace. I prefer Option 2, because I feel like it's easier to work with a local variable until you need to return it.
Edit:
Your comment said the loop runs infinitely, which means you're creating a brand new interval and reassigning the timer variable every time. This is a separate problem from the one I described above. The old interval is still out there, timer just doesn't point to it anymore. So how can clearInterval(timer) clear out all those intervals? It can't, it can only clear the most recent one.
Basically, you've got a whole bunch of timers all trying to make the thing blink at once.
How you deal with this depends on what you're trying to do. The simplest thing would be to keep no more than one interval running at once, which means you have to clear timer every time.
//same as option 1 above except for `clearInterval(timer)` at the
//beginning of `blinking`
var timer = null;
if (data.dash_notify == '1') {
var x = '#dash_notif_blink';
function blinking(x) {
clearInterval(timer);
timer = setInterval(blink, 10);
If you need multiple timers running, you'll have to keep track of them all in an array or something:
var timers = [];
//...
function blinking(x) {
timers.push(setInterval(blink, 10));
//...
} else if (!data.dash_notify) {
timers.forEach(function(timer) {
clearInterval(timer);
});
}
Not sure what you did wrong with your typeof check since you did not actually show the whole code, but it should look something like this:
if (typeof timer != "undefined" && timer) {
clearInterval(timer);
}
Basically define your variable timer before you enter your checking procedure (loop?):
var timer;
... some code ...
if ( data.dash_notify && data.dash_notify == '1') {
...
} else if (!data.dash_notify) {
clearInterval(timer);
}
You can call clearInterval( whatever ) without any consequences. Even if whatever is null, undefined, string and so on. Just make sure timer exist.
Passing an invalid ID to clearTimeout does not have any effect (and
doesn't throw an exception). (MDN)
You're getting that error because timer is only declared/initialized in the blinking function. In the place where you call clearInterval(timer), timer doesn't exist.
This is now working beautifully.
*Thank you to everyone who helped!*
if(data.dash_notify === '1' && t === null ){
var x = '#dash_notif_blink';
function blinking(x) {
var timer = setInterval(blink, 10); //note the var keyword for best practice
function blink() {
x.fadeOut(400, function () {
x.fadeIn(400);
});
}
return timer;
}
console.log('initiate_dash_alert');
// Data is passed. Parse to see if dash alert should be called. Secondary protection for
// multiple timer creation.
if(t){return;}else{t = blinking($(x));}
}else if (!data.dash_notify){
clearInterval(t);
console.log('clear_dash_alert');
t = null;
}else{
console.log(t);
console.log('no_push_events');
}
I've been playing around with a site, in which I want to continue clicking a button for i amount of times every interval seconds.
My code is:
clickbidBtn1 = function() {
var bidBtn=document.getElementById("BidButton");
var interval = 15000;
for (var i=3; i>=0; i--){
setTimeout(bidBtn.click(1);,i*interval);
};
I've found out that GM executes all i amount of clicks at the same time, not with the intended delay. is there a way to delay the time of click? Say i wanted the function to click the button every 15 second for i amount of times.
I was thinking of giving it some more variables, and adding one variable in the settimeout code part, which only executes # the click, then comparing increased variables with current ones before going to the next settimeout... but haven't thought it through yet... it seems to be a complicated process for a simple process... :( i wll play around with it a bit
Use setInterval() for this.
One way:
var bidClickTimer = 0;
var numBidClicks = 0;
function clickbidBtn1 ()
{
var interval = 15000;
bidClickTimer = setInterval (function() {BidClick (); }, interval);
}
function BidClick ()
{
numBidClicks++;
if (numBidClicks > 3)
{
clearInterval (bidClickTimer);
bidClickTimer = "";
}
else
{
bidBtn.click (1);
}
}
clickbidBtn1 ();
Alternatively, without using global vars:
function clickbidBtn1 ()
{
var interval = 15000;
this.numBidClicks = 0;
this.bidClickTimer = 0;
this.BidClick = function () {
numBidClicks++;
if (numBidClicks > 3)
{
clearInterval (bidClickTimer);
bidClickTimer = "";
}
else
{
bidBtn.click (1);
}
};
this.bidClickTimer = setInterval (function(thisScope) {thisScope.BidClick (); }, interval, this);
}
clickbidBtn1 ();
Just to explain why your code does not work: You are calling the .click method immediately (putting () after a function name calls the function) and actually passing the return value of that function to setTimeout. The for loop is so fast that everything seem to happen at the same time.
You have to pass a function reference to setTimeout, e.g. an anonymous function:
setTimeout(function() {
bidBtn.click(1);
}, i*interval);
I see there are lot's of threads here in SO about asking for a javascript sleep function and I know it can be done only using setTimeout and setInterval.
I do some userscripting with greasemonkey and written a script that loads a lot of pages and calculates something from them. It works, but I don't want to request the pages too fast.
var html0=syncGet(url0); // custom function for sync ajax call.
// fill the something array
for(var i=0;i<something.length;i++)
{
// calculate url1,url2 using the array and the i variable
// do something with lots of local variables
var html1=syncGet(url1);
// I would put a sleep here.
// do something with the results
var html2=syncGet(url2);
// I would put a sleep here.
// do something with the results
// get url3 from the page loaded from url2
var html3=syncGet(url3);
// I would put a sleep here.
// do something with the results
}
// use the result of the for loop and lots of code will follow...
The actual code is a bit more complex and longer than this.
I'm crying for the nonexistent sleep function (and understand why is it not possible) How to refactor this to use setTimeout, setInterval functions and keep it readable (and working) too?
For example this:
var urls = ["your","u","r","l´s"];
var htmls = new Array(urls.length);
var time = 1000;
for(var i=0;i<urls.length;i++){
(function(i){
setTimeout(function(){
htmls[i] = syncGet(urls[i]);
if(i == urls.length-1){
//continue here
}
},time*i);
})(i);
}
I had a similar problem where a big loop was blocking the whole browser in some older browsers, I solved it using :
function handlenext(idx,length) {
idx++
//do your stuff here base on idx.
if (idx < length) {
setTimeout(function(){handlenext(idx,length)},1)
} else {
initSuccessEnd()
}
}
var ln = something.length;
if (ln>0) {
handlenext(0,ln);
} else {
initSuccessEnd()
}
here initSuccessEnd is a callback function called when all is finished ..
After a research I think Mozilla's new iterator-generator stuff could be the most apropriate. (It's supported since FF2)
function doSomething()
{
//.....
var html=syncGet(url1);
yield true;
var html2=syncGet(url2);
yield true;
var html3=syncGet(url3);
yield true;
//......
yield false;
}
function iteratorRunner(iterator,timeout)
{
if (iterator.next())
{
setTimeout(function(){iteratorRunner(iterator,timeout)},timeout);
}
else
{
iterator.close();
}
}
var iterator=doSomething(); // returns an iterator immediately
iteratorRunner(iterator,1000); // runs the iterator and sleeps 1 second on every yield.
I hope greasemonkey will handle that...