So.. I have a webpage with a javascript function I wish to execute..
Not knowing javascript very well I exectue the function through the url bar..
javascript: Myfunct1();
javascript: Myfunct2();
Now what I really need to be able to do is a long sleep, execute the first function, sleep for a little, then execute the second function, then loop forever.. something like:
javascript: while(1) { Sleep(20000); Myfunct1(); Sleep(5000); Myfunct2() };
Obviously there isn't a 'Sleep' function.. and this is my problem.. After looking at various posts about 'setTimeout;, I tried that but have been unable to get it right.. was wondering if somebody would take pitty and a poor javascript simpleton and show me the way to do this?
have a look at setTimeout(). This will give you the delay you're looking for.
http://www.w3schools.com/js/js_timing.asp
Just pop this into your HTML before the </body> tag
<script type="text/javascript"><!--
setTimeout(function(){
Myfunct1();
setTimeout(function(){
Myfunct2();
},5000);
},20000);
--></script>
You can use setInterval in conjuction with setTimeout function:
setTimeout('Myfunct1(); setInterval("Myfunct1();", 25000);', 20000);
setTimeout('Myfunct2(); setInterval("Myfunct2();", 25000);', 25000);
This will accomplish the functionality like in your example without hanging the browser. Basicallly, it will Myfunct1() after 20s, and set it to run again 25s after that. Same thing is with Myfunct2(), except that it first run after 25s.
Here's a function that allows you to call alternating functions, waiting a specified amount of time between each invocation:
function alt(fn1, tm1, fn2, tm2) {
var curr, time;
(function next() {
curr = (curr === fn1) ? fn2 : fn1;
time = (time === tm1) ? tm2 : tm1;
window.setTimeout(function() {
curr();
next();
}, time);
})();
}
Use it like this:
alt(Myfunct1, 20000,
Myfunct2, 5000);
This will wait 20 seconds, then call Myfunct1, then wait 5 seconds and call Myfunct2, then wait 20 seconds and call Myfunct1 again, and so on.
Here's a general purpose version that accepts any number of function/timeout pairs:
function alt() {
var args = arguments;
(function next(i) {
if (i == args.length)
i = 0;
window.setTimeout(function() {
args[i]();
next(i + 2);
}, args[i + 1]);
})(0);
}
It's used the same way, but can accept more than two pairs:
alt(function(){console.log("1")}, 2000,
function(){console.log("2")}, 1000,
function(){console.log("3")}, 5000);
If this were real code there's a lot more you could do, like verify arguments and/or specify default timeouts when not provided for any of the given functions.
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] || '';
}
}
here is my pseudo code
var list = {
a:[
{content: 'a', time: 5},
{content: 'b', time:2},
{content: 'c', time:3}]
}
var insert_and_stop = function(content, time){
//let content insert to somewhere and wait for "time" second
}
my requirement is running a loop to insertSome(content, time) on dataset(list)
and start over again to the head of list
obviously, I can use for to run my function on list
but I don't know how to start over?
Sorry for incomplete code
Update !!!
my solution right now is:
for(var i = 0; i<list.a.length; i++){
(function(i){
setTimeout(insert(list.a[i].content), list.a[i].time * 1000);
})(i);
}
it works but i don't if I let while(true) include this code
the browser will crash because the for... part will run repeatly
I think what pid meant to say in his answer is that you should use:
setInterval(function, delay)
Where function is the function name and delay is the delay in milliseconds between invocations.
Using your code as a reference and your query, here is how I would approach it:
var list = {
a:[
{content: 'a', time: 5},
{content: 'b', time:2},
{content: 'c', time:3}]
}
var i = 0;
var insertContent = function(){
// Do something with the content
console.log(list.a[i].content);
// Either increment the i or restart at 0.
if((list.a.length - 1) > i ){
i++;
}else{
i = 0;
}
setTimeout(function(){
// Run the function again
insertContent();
}, list.a[i].time * 1000);
}
This code will loop until the end of the array and then starts again.
I have tested it on my side and seems to be working, however I did rename the function, so just adapt it according to your requirements.
The two options here are setInterval(function, delay) and setTimeout(function, delay). The main difference being, that setInterval will fire exactly each delay time period, while setTimeout will only fire when the internal code has been run. In practice, you would have to look out for side effects in case of code that runs for longer than you'd expect (and that would cause setInterval to stack the code on top of itself multiple times).
Examples:
function myTimeoutFunc(){
// .. some code
setTimeout(myFunc, delay-in-milliseconds);
}
myFunc();
function myIntervalFunc(){
// .. some code
}
setInterval(myIntervalFunc, delay-in-milliseconds);
Use setInterval(<function-name>, <delay-in-milliseconds>) where <function-name> is the function name or a lambda (if you know what this is) and <delay-in-milliseconds> is the delay in milliseconds between invocations.
Otherwise, if you actually need to do it inside insert_and_stop() you can do as follows. Write an actual function (this means you need just 1 exit point). Then, just before you exit your function:
setTimeout(function () { insert_and_stop(content, time); }, time);
You need the lambda (the wrapping function) because the parameters content and time need to be passed correctly for the subsequent invocations.
Note that this will not invoke your function every <time> milliseconds because the execution time of the function itself is not accounted for. If insert_and_stop() takes a time that is similar to <time> this effect might become sensible. Otherwise, if the function is quick (microseconds) and the interval is high (100 or 1000 times as long) then the overhead may be negligible, based on what you are actually doing.
//set my function each 3seconds
var interval = setInterval("myFunction", 3000);
//or
var interval = setInterval(function(){
alert("I am myFunction");
}, 3000);
//release
releaseInterval(interval);
It's important "setInterval" return value that needs to release!
I've been reading about setTimeout and other such timers. But I'm wondering if it's possible to work up a custom function so that all you would need to do is something like this:
//code
delay(time);
//more code
Is this possible?
UPDATE: Ok, I kind of get it. So if that isn't reasonably possible, how would you go about delaying a loop AFTER the first time. I want it to run immediately upon execution but they delay on each iteration afterward.
New UPDATE: I figure since my initial thought fell through, it might just be easier to show you the code I have.
function autoFarm (clickEvent){
var farmTargets = [
"6_300_1",
"6_300_3",
"6_300_4",
"6_300_5",
"6_300_7"];
setTimeout(function() {
$.each (farmTargets, function(index, target){
var extraData = '{"end_pos":"' + target + '","purpose":0,"upshift":1,"bring_res":{"0":0,"2":0,"1":0},"bring_ship":{"1":25,"11":0},"rate":100,"start_pos":"6_300_2"}';
var finalData = baseDataDora + extraData + "&type=1";
setTimeout(function(){
for (i = 0; i < farmTargets.length; i++){
postRequest(sendFleetURL + getSign(extraData). finalData, function(json){
});
}
}, 15000);
});//End each loop
}, 1320000);
}//End autoFarm
Basically, it should execute immediately and run the for loop 5 times on the first array element 15 seconds apart. Then 22 minutes later move to the next set and repeat for the entire array.
You can achieve something along those lines with generators. The idea is that continuation passing style (callback hell) can be flattened. The generator uses the yield keyword to pause the function, until the callback resumes it by calling its next method:
var async = function(gen) {
var g = gen()
function next(x) {
var cur = g.next(x)
if (cur.done) {
return cur.value
}
cur.value(next)
}
next()
}
var delay = function(time) {
return function(f) {
setTimeout(f, time)
}
}
async(function* () {
console.log('before')
yield delay(1000) // waits one second
console.log('middle')
yield delay(1000) // waits one second
console.log('after')
})
In CPS it would read something like:
console.log('before')
setTimeout(function() {
console.log('middle')
setTimeout(function() {
console.log('after')
}, 1000)
}, 1000)
This works in Chrome, Firefox and iojs today.
This isn't possible because of the way single-threaded event loops work. If this function were to exist, it would cause the entire UI thread to freeze until the delay was satisfied. setTimeout(cb, delay) is the nearest facility which schedules a function to be executed no earlier than the delay and at the end of the current event loop tick.
Update: Before somebody calls me on it, yes, you can theoretically engineer a delay function that freezes everything in place for a set amount of time. However, there is no reasonable excuse to do it this way.
To your second question:
function hello() {
console.log('hello');
}
// execute immediately
hello();
// then every 5 seconds
setInterval(hello, 5000);
As-written, no that's not possible.
If, instead you were to use a queue, delays in that manner are trivial.
jQuery's .queue() and .delay() functions are a good example of how this works, so I will use them as an example, however the general point stands for any queueing library.
Instead of:
//code
delay(time)
//more code
With a queue, you'd write:
$('...') //some selector to act on for jQuery
.queue(function (next) {
//code
//Indicate that the queued call is finished.
next();
//This allows async code to be executed in the queue,
//such as ajax and animations
})
.delay(time)
.queue(function (next) {
//more code
next();
});
Now, even if you ignore the lines used for comments, you can tell that there's a bit more boilerplate to achieve the desired behavior. I don't feel that it's excessive, because I find it relatively easy to read:
queue something to happen
wait for some number of milliseconds
queue something else to happen
Using a Promise, calling it inside an asynchronous function.
const delay = (ms) => new Promise(resolve => setTimeout(resolve, ms));
const any_function = async() => {
await delay(2000);
console.log('this log has been delayed 2 secs')
}
Sorry if this question has already been asked here before, I could not find a suitable answer.
I am wanting to create a JavaScript sleep/delay/wait function that I can call anywhere in the script, like jQuery's .delay()
I am not able to use setTimeout, as I have a script that is generated by php, and so am not able to put it into two different functions, with the timeout in the middle. I need to create a function that allows me to do
alert("time started");
sleep(4000);
alert("time up");
I really do not want to use jQuery.
Here's a solution using the new async/await syntax.
async function testWait() {
alert('going to wait for 5 second');
await wait(5000);
alert('finally wait is over');
}
function wait(time) {
return new Promise(resolve => {
setTimeout(resolve, time);
});
}
Note: You can call function wait only in async functions
You cannot just put in a function to pause Javascript unfortunately.
You have to use setTimeout()
Example:
function startTimer () {
timer.start();
setTimeout(stopTimer,5000);
}
function stopTimer () {
timer.stop();
}
EDIT:
For your user generated countdown, it is just as simple.
HTML:
<input type="number" id="delay" min="1" max="5">
JS:
var delayInSeconds = parseInt(delay.value);
var delayInMilliseconds = delayInSeconds*1000;
function startTimer () {
timer.start();
setTimeout(stopTimer,delayInMilliseconds);
}
function stopTimer () {
timer.stop;
}
Now you simply need to add a trigger for startTimer(), such as onchange.
You will have to use a setTimeout so I see your issue as
I have a script that is generated by PHP, and so am not able to put it into two different functions
What prevents you from generating two functions in your script?
function fizz() {
var a;
a = 'buzz';
// sleep x desired
a = 'complete';
}
Could be rewritten as
function foo() {
var a; // variable raised so shared across functions below
function bar() { // consider this to be start of fizz
a = 'buzz';
setTimeout(baz, x); // start wait
} // code split here for timeout break
function baz() { // after wait
a = 'complete';
} // end of fizz
bar(); // start it
}
You'll notice that a inside baz starts as buzz when it is invoked and at the end of invocation, a inside foo will be "complete".
Basically, wrap everything in a function, move all variables up into that wrapping function such that the contained functions inherit them. Then, every time you encounter wait NUMBER seconds you echo a setTimeout, end the function and start a new function to pick up where you left off.
The behavior exact to the one specified by you is impossible in JS as implemented in current browsers. Sorry.
Well, you could in theory make a function with a loop where loop's end condition would be based on time, but this would hog your CPU, make browser unresponsive and would be extremely poor design. I refuse to even write an example for this ;)
Update: My answer got -1'd (unfairly), but I guess I could mention that in ES6 (which is not implemented in browsers yet, nor is it enabled in Node.js by default), it will be possible to write a asynchronous code in a synchronous fashion. You would need promises and generators for that.
You can use it today, for instance in Node.js with harmony flags, using Q.spawn(), see this blog post for example (last example there).
You can use this -
function sleep(milliseconds) {
var start = new Date().getTime();
for (var i = 0; i < 1e7; i++) {
if ((new Date().getTime() - start) > milliseconds){
break;
}
}
}
You could use the following code, it does a recursive call into the function in order to properly wait for the desired time.
function exportar(page,miliseconds,totalpages)
{
if (page <= totalpages)
{
nextpage = page + 1;
console.log('fnExcelReport('+ page +'); nextpage = '+ nextpage + '; miliseconds = '+ miliseconds + '; totalpages = '+ totalpages );
fnExcelReport(page);
setTimeout(function(){
exportar(nextpage,miliseconds,totalpages);
},miliseconds);
};
}
Is there any JavaScript method similar to the jQuery delay() or wait() (to delay the execution of a script for a specific amount of time)?
Just to add to what everyone else have said about setTimeout:
If you want to call a function with a parameter in the future, you need to set up some anonymous function calls.
You need to pass the function as an argument for it to be called later. In effect this means without brackets behind the name. The following will call the alert at once, and it will display 'Hello world':
var a = "world";
setTimeout(alert("Hello " + a), 2000);
To fix this you can either put the name of a function (as Flubba has done) or you can use an anonymous function. If you need to pass a parameter, then you have to use an anonymous function.
var a = "world";
setTimeout(function(){alert("Hello " + a)}, 2000);
a = "Stack Overflow";
But if you run that code you will notice that after 2 seconds the popup will say 'Hello Stack Overflow'. This is because the value of the variable a has changed in those two seconds. To get it to say 'Hello world' after two seconds, you need to use the following code snippet:
function callback(a){
return function(){
alert("Hello " + a);
}
}
var a = "world";
setTimeout(callback(a), 2000);
a = "Stack Overflow";
It will wait 2 seconds and then popup 'Hello world'.
There is the following:
setTimeout(function, milliseconds);
function which can be passed the time after which the function will be executed.
See: Window setTimeout() Method.
Just to expand a little... You can execute code directly in the setTimeout call, but as #patrick says, you normally assign a callback function, like this. The time is milliseconds
setTimeout(func, 4000);
function func() {
alert('Do stuff here');
}
If you really want to have a blocking (synchronous) delay function (for whatsoever), why not do something like this:
<script type="text/javascript">
function delay(ms) {
var cur_d = new Date();
var cur_ticks = cur_d.getTime();
var ms_passed = 0;
while(ms_passed < ms) {
var d = new Date(); // Possible memory leak?
var ticks = d.getTime();
ms_passed = ticks - cur_ticks;
// d = null; // Prevent memory leak?
}
}
alert("2 sec delay")
delay(2000);
alert("done ... 500 ms delay")
delay(500);
alert("done");
</script>
You need to use setTimeout and pass it a callback function. The reason you can't use sleep in javascript is because you'd block the entire page from doing anything in the meantime. Not a good plan. Use Javascript's event model and stay happy. Don't fight it!
You can also use window.setInterval() to run some code repeatedly at a regular interval.
To add on the earlier comments, I would like to say the following :
The setTimeout() function in JavaScript does not pause execution of the script per se, but merely tells the compiler to execute the code sometime in the future.
There isn't a function that can actually pause execution built into JavaScript. However, you can write your own function that does something like an unconditional loop till the time is reached by using the Date() function and adding the time interval you need.
If you only need to test a delay you can use this:
function delay(ms) {
ms += new Date().getTime();
while (new Date() < ms){}
}
And then if you want to delay for 2 second you do:
delay(2000);
Might not be the best for production though. More on that in the comments
why can't you put the code behind a promise? (typed in off the top of my head)
new Promise(function(resolve, reject) {
setTimeout(resolve, 2000);
}).then(function() {
console.log('do whatever you wanted to hold off on');
});
The simple reply is:
setTimeout(
function () {
x = 1;
}, 1000);
The function above waits for 1 second (1000 ms) then sets x to 1.
Obviously this is an example; you can do anything you want inside the anonymous function.
I really liked Maurius' explanation (highest upvoted response) with the three different methods for calling setTimeout.
In my code I want to automatically auto-navigate to the previous page upon completion of an AJAX save event. The completion of the save event has a slight animation in the CSS indicating the save was successful.
In my code I found a difference between the first two examples:
setTimeout(window.history.back(), 3000);
This one does not wait for the timeout--the back() is called almost immediately no matter what number I put in for the delay.
However, changing this to:
setTimeout(function() {window.history.back()}, 3000);
This does exactly what I was hoping.
This is not specific to the back() operation, the same happens with alert(). Basically with the alert() used in the first case, the delay time is ignored. When I dismiss the popup the animation for the CSS continues.
Thus, I would recommend the second or third method he describes even if you are using built in functions and not using arguments.
As other said, setTimeout is your safest bet
But sometimes you cannot separate the logic to a new function then you can use Date.now() to get milliseconds and do the delay yourself....
function delay(milisecondDelay) {
milisecondDelay += Date.now();
while(Date.now() < milisecondDelay){}
}
alert('Ill be back in 5 sec after you click OK....');
delay(5000);
alert('# Im back # date:' +new Date());
delay function:
/**
* delay or pause for some time
* #param {number} t - time (ms)
* #return {Promise<*>}
*/
const delay = async t => new Promise(resolve => setTimeout(resolve, t));
usage inside async function:
await delay(1000);
Or
delay(1000).then(() => {
// your code...
});
Or without a function
new Promise(r => setTimeout(r, 1000)).then(() => {
// your code ...
});
// or
await new Promise(r => setTimeout(r, 1000));
// your code...
I had some ajax commands I wanted to run with a delay in between. Here is a simple example of one way to do that. I am prepared to be ripped to shreds though for my unconventional approach. :)
// Show current seconds and milliseconds
// (I know there are other ways, I was aiming for minimal code
// and fixed width.)
function secs()
{
var s = Date.now() + ""; s = s.substr(s.length - 5);
return s.substr(0, 2) + "." + s.substr(2);
}
// Log we're loading
console.log("Loading: " + secs());
// Create a list of commands to execute
var cmds =
[
function() { console.log("A: " + secs()); },
function() { console.log("B: " + secs()); },
function() { console.log("C: " + secs()); },
function() { console.log("D: " + secs()); },
function() { console.log("E: " + secs()); },
function() { console.log("done: " + secs()); }
];
// Run each command with a second delay in between
var ms = 1000;
cmds.forEach(function(cmd, i)
{
setTimeout(cmd, ms * i);
});
// Log we've loaded (probably logged before first command)
console.log("Loaded: " + secs());
You can copy the code block and paste it into a console window and see something like:
Loading: 03.077
Loaded: 03.078
A: 03.079
B: 04.075
C: 05.075
D: 06.075
E: 07.076
done: 08.076
The simplest solution to call your function with delay is:
function executeWithDelay(anotherFunction) {
setTimeout(anotherFunction, delayInMilliseconds);
}