Javascript, setting timeout between events in one function - javascript

lets say I have a function in a loop that will display two different kinds of text interchangeably over and over.
Now what I want to achive is for the different text to be displayed with a delay, let's say 1 second. So it would print 1st text and after 1 second 2nd text and so on untill the loop is over. I was trying to use setTimeout and setInterval but I cannot get it to work.
var a = "hey ";
var b = "ho ";
function test(a,b){
document.getElementById('id').innerHTML += a;
document.getElementById('id').innerHTML += b;
}
for(var i = 0; i < 10; i++){
setInterval(test(a,b), 1000);
}
<div id="id">
</div>

You need to use setTimeout to introduce delay and not setInterval.
Timeout should be in incremental order so multiply it with i
test(a,b) should be in callback of the function so that setTimeout can execute it based on the delay. If you will directly write test(a,b) then it will get executed right then and there without any delay.
var a = "hey ";
var b = "ho ";
function test(a,b){
document.getElementById('id').innerHTML += a;
setTimeout(function(){
document.getElementById('id').innerHTML += b;
}, 500)
}
for(var i = 0; i < 10; i++){
setTimeout(function(){
test(a,b);
}, i*1000);
}
<div id="id">
</div>
UPDATE
Delay between document.getElementById('id')

You could use a setInterval and keep track of how many were done with a variable :
var count = 0; //Variable to keep track of the number of setInterval called
var text = ['text1','text2'];
var interval = setInterval(() => {
if(count == 10) clearInterval(interval); //Stop the setInterval when you reach the 10th time
document.getElementById('test').innerHTML = count % 2 == 0 ? text[0] : text[1];
count++; //Increment your var
},1000);
<div id="test"></div>

You can use an "asynchonous" loop for this, i.e. a function that calls itself after a time out. Then use the modulo operator to decide whether to show a or b:
var a = "hey ";
var b = "ho ";
function test(c){
document.getElementById('id').innerHTML += c;
}
(function loop(i){
if (i >= 10) return; // All done
test(i%2 ? b : a); // choose which one to show
setTimeout(loop.bind(null, i+1), 1000); // Repeat with delay and incremented i.
})(0); // Start the loop immediately with i=0
<div id="id">
</div>

function loop(i, limit) {
if (i < limit) {
console.log('Text 1');
setTimeout(function() {
console.log('Text 2');
setTimeout(function() {
loop(++i,limit);
},1000);
},1000);
}
}
loop(0,3);

You need to change your code around a bit to introduce a delay between each.
The code below:
stores the possible values in the array
has a method which will display the ith element from the values
has a run method used to start the loop, and also recalled with a delay (1second) having incremented a counter
var values = ["hey","ho"];
var index = 0;
function display(i){
document.getElementById('id').innerHTML = values[i];
}
function run(){
display(index%values.length)
if(++index<10){
setTimeout(run,1000);
}
}
run();
<div id="id">
</div>

If you want the timeout between 'hey' and 'ho' also, you shouldn't be keeping both of them inside test, instead keep only one and change the param value.
var a = "hey ";
var b = "ho ";
function test(a){
document.getElementById('id').innerHTML += a;
}
for(var i = 0; i < 10; i++){
(function(i) {
setTimeout(function(){
test(i % 2 === 0 ? a : b);
}, i*1000);
}(i))
}
<div id="id">
</div>

Related

Count down and change variable as it happens [duplicate]

This question already has answers here:
Javascript wait() function [closed]
(2 answers)
Closed 3 years ago.
I am running a for loop with a break of 1 second between each iteration:
<html>
<body>
<script>
var text = "";
var i;
// Wait function
function wait(ms){
var start = new Date().getTime();
var end = start;
while(end < start + ms) {
end = new Date().getTime();
}
}
for (i = 0; i < 5; i++) {
text += "The number is " + i + "<br>";
wait(100)
}
</script>
<script>document.write(text)</script>
</body>
Currently, when I open the file in a web browser, the browser window is loading until the for loop has finished and then the results are displayed (five output lines). Is there a way to display the out put "as it happens". With this I mean, I open the page and every second a new line is printed.
Thank you!
You should learn about timeout and interval concepts in Javascript.
Here is code that will do the work. Examine it.
<html>
<body>
<script>
function waitAndWrite(num) {
setTimeout(() => {
let text = "The number is " + num + "<br>";
document.write(text)
}, num * 1000)
}
for (let i = 0; i < 5; i++) {
waitAndWrite(i)
}
</script>
</body>
Instead of using your own "wait" function, you could use setInterval(fn, timeout) src instead.
var i = 0;
var interval = setInterval(() => {
i = i + 1;
if(i === 5) {
clearInterval(interval);
}
document.write("Your text " + i);
}, 1000);
What you are trying to achieve manually, you can achieve the same with WindowOrWorkerGlobalScope.setTimeout():
The setTimeout() method of the WindowOrWorkerGlobalScope mixin (and successor to Window.setTimeout()) sets a timer which executes a function or specified piece of code once the timer expires.
for (let i = 0; i < 5; i++) {
setTimeout(() => document.write("The number is " + i + "<br>"), 1000 * i); // multiply the delay with i in each iteration
}

How define a couple of setIntervals and clear them with delay

I need to randomly change characters of a text and after some delay fix them.
There is my code:
<h1 id="text" style="margin-top:100px;">SOME TEXT</h1>
<script>
var text = document.getElementById("text").innerHTML.split("");
var myArr = text;
for (i = 0; i < myArr.length; ++i) {
var handle = setInterval(function () { xyz(i) }, 100);
setTimeout(function (handle) {
myArr[i] = text[i];
clearInterval(handle);
}, (i) * 1000);
}
function xyz(index) {
myArr[index] = String.fromCharCode(Math.random() * 26 + 65);
document.getElementById("text").innerHTML = myArr;
}
</script>
It seems i have no a good understanding of how setInterval work! :(
EDIT:
With my code only text[text.length+1] character has change that mean passed parameter to xyx() function is last value of loop counter variable (after loop over). Now my question is how trigger setInterval() function with i = 0 ,1 ... , text.length.
Can someone guide me?
basicly setInterval execute a function with a iteration in time. and setInterval gives you a promise to cancel it any time you want.
var myPromise = setInterval(function(){
//some code here
},delayMiliseconds);
to cancel this code
clearInterval(myPromise);
Related to this question problem was wrong way to passing arguments to setInterval().the callback function i passed to setInterval() maintains a reference to "i" rather than the snapshot value of "i" as it existed during each particular iteration...
<h1 id="text" style="margin-top:100px;">SOME TEXT</h1>
<script>
var text = document.getElementById("text").innerHTML.split("");
var myArr = document.getElementById("text").innerHTML.split("");
for (i = 0; i < text.length; i++) {
var handle = setInterval(function (k) { xyz(k) }, 100,i);
setTimeout(function (handle, i) {
console.log(i);
console.log(text[i]);
myArr[i] = text[i];
clearInterval(handle);
}, (i) * 1000,handle,i);
}
function xyz(index) {
myArr[index] = String.fromCharCode(Math.random() * 26 + 65);
document.getElementById("text").innerHTML = myArr.toString();
}
</script>

Running text effect

I have some words like "beautiful","awesome","nice" and "wonderful".
i want to show the each word as typing text effect one after one for infinite time.
see i want like this :google forms
I have made the running text effect.
see the code below:
var myText= "beautiful";
var text = myText.split("");
var counter = 0;
function typeIt(text){
var SI=setInterval(function(){
var h1 = $("#myTypingText");
h1.append(text[counter]);
counter++;
if(counter==text.length){
clearInterval(SI);
}
},70);
}
i am not able to run this function for each word one after one for infinite time.
please help me to resolve this.
thanks in advance.
You can modify your existing function to accept an array of words, and process the words one by one.
EDIT: Expand this first snippet to see my original answer that has no delay in between words:
function typeIt(words) {
var letterIndex = 0;
var wordIndex= 0;
var h1 = $("#myTypingText");
var SI = setInterval(function() {
if (letterIndex === words[wordIndex].length) { // if at end of current word
wordIndex = (wordIndex + 1) % words.length; // go to next word
letterIndex = 0;
h1.empty(); // clear output div
}
h1.append(words[wordIndex][letterIndex]);
letterIndex++;
}, 70);
}
typeIt(["beautiful", "awesome", "nice", "wonderful"]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="myTypingText"></div>
Note that you don't need to .split("") the word, because you can directly reference the individual characters in a string with the same square-bracket syntax as referencing array elements, e.g., "text"[2] is "x".
You can use setTimeout() to control the delay in between words:
function typeIt(words) {
var letterIndex = 0;
var wordIndex = 0;
var h1 = $("#myTypingText");
(function nextWord() {
var SI = setInterval(function() {
h1.append(words[wordIndex][letterIndex]);
letterIndex++;
if (letterIndex === words[wordIndex].length) {
wordIndex = (wordIndex + 1) % words.length;
letterIndex = 0;
clearInterval(SI);
setTimeout(function() {
h1.empty();
nextWord();
}, 1000); // delay between words
}
}, 70); // delay between letters
})();
}
typeIt(["beautiful", "awesome", "nice", "wonderful"]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="myTypingText"></div>
Note that this isn't necessarily the cleanest way to structure the code, but it seemed the quickest way to modify what you already had to achieve the desired output.
Further reading: Immediately Invoked Function Expressions (IIFEs).

DOM Manipulation not executing instantly

I've experienced the issue that DOM Manipulations only take effect when the browser ran through all iterations, i.e. while, for, -loops.
Example:
var text = document.getElementById("text");
for (var i = 0; i < 100000000; i++) {
if (i % 1000000 == 0) {
setTimeout(function() {
text.innerHTML += "|";
}, 0);
}
}
<p id="text"></p>
I'd like to see a progressbar-ish behavior, instead the DOM is manipulated only when he ran through the for-loop.
I tried an asynchronous approach with setTimeout with no success.
Is there a good way to achieve this?
Instead of using loops and setTimeout, use the similar Javascript tool setInterval. This will run a function repeatedly every N milliseconds. You can use a counter variable to keep track of when to add progress bars and when to stop! http://jsfiddle.net/4odd386e/
var text = document.getElementById("text");
var i = 0;
function addOne() {
i += 1;
if (i % 10 === 0) {
text.innerHTML += "|";
}
if (i === 1000) {
// Progress complete
clearInterval(initProgress);
}
}
var initProgress = setInterval(addOne, 0);
Also, the high numbers you initially used were causing very slow progress, so I used 10 and 1000 as examples. This code will work with higher numbers, but it will take a long time to show results.
Change the timeout from 0 to 500, and you will see it progress:
var text = document.getElementById("text");
for (var i = 0; i < 100000000; i++) {
if (i % 1000000 == 0) {
setTimeout(function() {
text.innerHTML += "|";
}, 500);
}
}
<p id="text"></p>
However, the program has to finish counting to 100 million before it goes into an idle state to handle the first timer.
Here's an alternative method, which won't take up so many computer resources:
var text = document.getElementById("text");
for (var i = 0; i < 100; i++) {
setTimeout(function() {
text.innerHTML += "|";
}, 10*i);
}
<p id="text"></p>
Since Javascript runs in a single thread and therefore everything is blocked until it is finished processing the calculations.
In order to have a non-blocking calculation, you can use webworkers and update the dom when the worker dispatches the postMessage event.
Example:
Main code:
var text = document.getElementById("text");
var myWorker = new Worker("js/forloop.js");
myWorker.postMessage(2000);
myWorker.onmessage = function(e) {
//e.data is an object which is passed from the worker
if (e.data === true)
text.innerHTML += "|";
}
WebWorker code:
onmessage = function(e) {
for (var i = 0; i < e.data; i++) {
postMessage(true);
}
}
Further reading: Webworkers

setTimeout inside for loop [duplicate]

This question already has answers here:
setTimeout in for-loop does not print consecutive values [duplicate]
(10 answers)
Closed 7 years ago.
I want a string to appear character-for-character with the following code:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout('textScroller.innerHTML += text[c]', 1000);
}
}
window.onload = initText;
It's not working.. what am I doing wrong?
Try something like this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = setInterval(function() {
textScroller.innerHTML += text[c];
c++;
if(c >= text.length) clearInterval(interval);
}, 1000);
}
Note I added clearInterval to stop it when it's needed.
Currently, you are defining 18 timeouts and all will be executed ~ at once.
Second problem is, you pass instructions to execute as a String. In that case, the code won't have access to all variables defined in initText, because evaluated code will be executed in global scope.
IMO, this should do the job
function initText(){
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
(function(){
textScroller.innerHTML += text.charAt(c++);
if(text.length > c){
setTimeout(arguments.callee, 1000);
}
})();
}
Even more generic than answer by #yauhen-yakimovich:
Using Timeout:
var repeat = (function () {
return function repeat(cbWhileNotTrue, period) {
/// <summary>Continuously repeats callback after a period has passed, until the callback triggers a stop by returning true. Note each repetition only fires after the callback has completed. Identifier returned is an object, prematurely stop like `timer = repeat(...); clearTimeout(timer.t);`</summary>
var timer = {}, fn = function () {
if (true === cbWhileNotTrue()) {
return clearTimeout(timer.t); // no more repeat
}
timer.t = setTimeout(fn, period || 1000);
};
fn(); // engage
return timer; // and expose stopper object
};
})();
Using Interval:
var loop = (function () {
return function loop(cbWhileNotTrue, period) {
/// <summary>Continuously performs a callback once every period, until the callback triggers a stop by returning true. Note that regardless of how long the callback takes, it will be triggered once per period.</summary>
var timer = setInterval(function () {
if (true === cbWhileNotTrue()) clearInterval(timer);
}, period || 1000);
return timer; // expose stopper
};
})();
Slight difference between the two indicated in comments -- the repeat method only repeats after the callback performs, so if you have a "slow" callback it won't run every delay ms, but repeats after every delay between executions, whereas the loop method will fire the callback every delay ms. To prematurely stop, repeat uses an object as the returned identifier, so use clearTimeout(timer.t) instead.
Usage:
Just like answer by #soufiane-hassou:
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
var interval = repeat/* or loop */(function() {
textScroller.innerHTML += text[c];
c++;
return (c >= text.length);
}, 1000);
As mentioned, premature stopping would be:
/* if repeat */ clearTimeout(interval.t);
/* if loop */ clearInterval(interval);
Try this:
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
for(c = 0; c < text.length; c++)
{
setTimeout("textScroller.innerHTML += '" + text[c] + "'", 1000 + c*200);
}
}
window.onload = initText;
Try using a closure:
function init() {
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
var c = 0;
function run() {
textScroller.innerHTML += text[c++];
if (c<text.length)
setTimeout(run, 1000);
}
setTimeout(run, 1000);
}
init()
The problem in your code is that the code you put in the string will run in the global context, where textScroller is not defined (it is defined inside your function).
I want to share a snippet (based on answer by Soufiane Hassou). It extends to the case when you literally replace a for-loop body to be iterated over some array in a fixed interval of time. Basically same synchronous loop but with "sleep" pausing (because javascript is not a synchronous programming language).
function loop(arr, take, period) {
period = period || 1000;
var i = 0;
var interval = setInterval(function() {
take(i, arr[i]);
if (++i >= arr.length) { clearInterval(interval);}
}, period);
}
Usage example:
loop([1, 2, 3, 4], function(index, elem){
console.log('arr[' + index + ']: ' + elem);
});
Tested in Node JS. Hope that helps someone.
edit>
the following update makes code usable together with libs doing heavy "prototyping" (like jQuery or prototype):
function loop(arr, take, period) {
period = period || 1000;
var scope = {
i: 0,
arr: arr,
take: take,
};
var iterate = (function iterate() {
if (this.i >= this.arr.length) { clearInterval(this.interval); return}
take(this.i, this.arr[this.i++]);
}).bind(scope);
scope.interval = setInterval(iterate, period);
}
Your for loop is setting a timeout for every character at once, so they will not appear in sequence, but all at once. Your setTimeout should include code to another setTimeout that will include the next character to display.
So something like this (didn't test this)
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = 'Hello how are you?';
setTimeout('nextChar(text)', 1000);
}
function nextChar(text){
if(text.length > 0){
textScroller.innerHTML += text[0];
setTimeout('nextChar(text.substring(1))', 1000);
}
}
If you want to preserve setTimeOut (instead of setInterval) and use named function (instead of evaluating code block in setTimeOut call), then this could be helpful:
var b = {
textScroller: document.getElementById('textScroller'),
text: "Hello how are you?"
};
function initText() {
for(c = 0; c < b.text.length; c++) {
setTimeout("append("+c+")", 1000 + c*200);
}
}
function append(c) {
b.textScroller.innerHTML += b.text[c];
}
window.onload = initText;
With the above you can pass a parameter to append function.
To pass several parameters the next code does the trick:
var glo = [];
function initText()
{
var textScroller = document.getElementById('textScroller');
var text = "Hello how are you?";
var timeout_time;
for(c = 0; c < text.length; c++) {
glo[glo.length] = {text:text, c:c, textScroller:textScroller};
timeout_time = 1000 + c * 200;
setTimeout("append(" + (glo.length - 1) + ")", timeout_time);
}
}
function append(i)
{
var obj = glo[i];
obj.textScroller.innerHTML += obj.text[obj.c];
obj = null;
glo[i] = null;
}
window.onload = initText;
With the above you have only one global array glo. In loop you create new array members to glo and in append() function refer to these members using index which is passed as parameter.
CAUTION: the second code sample is not meant as best or most suitable solution to OP:s problem, but may benefit in other setTimeOut relative problems, eg. when someone wants to make a presentation or performance test where some functionalities are needed to call after some delay. The advantage of this code is to make use of for loops (many coders want to use for loops) and the possibility to use also inner loops and the ability to "send" local variables in their loop time state to timeOut functions.
May be better to loop in cascade. For exemple to fade a div :
div=document.createElement('div');
div.style.opacity=1;
setTimeout(function(){fade(1);},3000);
function fade(op){
op-=.05;
if(op>0) setTimeout(function(){div.style.opacity=op;fade(op);},30);
else document.body.removeChild(div);
}

Categories

Resources