I have to run some code after some predefined irregular intervals after users takes some action like a button click.
The intervals could be [1, 1.2, 2.05, 2.8, ...., 10.56], [0.2, 1.5, 3.9, 4.67, 6.8, .., 12.0] or something else. So, the function should be called after 1 second, 1.2 seconds, 2.05 seconds and so on after the initial button click.
How can I do that in JavaScript?
You use setTimeout inside a function that gets called by that setTimeout:
// intervals in seconds
const intervals = [1, 1.2, 2.05, 2.8, 10.56];
(function runIrregularly(runThisCode) {
if (intervals.length > 0) {
// get (and remove) the first element from the array:
const timeout = intervals.shift();
// and schedule the next call to run in the future
setTimeout(
() => runIrregularly(runThisCode),
timeout * 1000
);
}
// then run our real function
runThisCode();
})(doSomething);
function doSomething() {
console.log(Date.now());
}
Now, while we're using shift() to get elements from the start of the array, you should at that point go "hm, so it doesn't even care that it's an array?" and indeed: because this code doesn't iterate over anything, you can even replace that with a generating function that comes up with values as needed:
function getNextInterval() {
// do whatever you like here
return some number;
}
(function runIrregularly(runThisCode) {
if (intervals.length > 0) {
const timeout = getNextInterval();
...
(You could even get fancy by using a generator function if you wanted)
Also, we don't have to call the function "as we declare it" of course, we can also declare and use it separately:
function runIrregularly(runThisCode) {
if (intervals.length > 0) {
...
}
runThisCode();
}
// and then at some later point in the code
runIrregularly(doSomething);
And finally, if you need this to cycle, rather than run once, we can combine shift with push, and copy the interval list when we start:
function runIrregularly(runThisCode, intervals) {
// get and remove the first element from the array
const timeout = intervals.shift();
// then push it back on as the last element.
intervals.push(timeout);
setTimeout(
() => runIrregularly(runThisCode, intervals),
timeout * 1000
);
runThisCode();
}
// and then later:
runIrregularly(doSomething, intervals.slice());
With the interval.slice() being necessary so that we leave the original array pristine (otherwise using for other functions will make those not start at your first interval, but "wherever we are in the cycle" based on however many calls are running).
How to capture and stop the timeouts, I leave as an exercise to the reader (there are plenty of questions/posts about that on the web/SO to find).
You can also achieve this with async/await in combination with setTimeout:
setTimeout(function() {
}, 1000);
Would execute function after 1 second has passed.
You can achieve your goal by nesting setTimeout calls (see answer by Mike) or with promises (async/await):
function delayExecution(n) {
return new Promise((resolve) => {
setTimeout(resolve, n)
})
}
async function runIrregularly(fn, delays) {
for (const delay of delays) {
// suspend execution by `delay` amounts of seconds
await delayExecution(delay * 1000)
fn()
}
}
runIrregularly(() => {
console.log(Date.now(), "Hello")
}, [1, 2, 3])
Related
How can I invoke three times a function with a setTimeOut but just print it once after 100 milliseconds??
This is the definition of debounce that I have to implement:
Debounce ignores the calls made to it during the timer is running and
when the timer expires it calls the function with the last function
call arguments, so I want to achieve that with Javascript
A function will be debounced as follows:
receivedEvent = debounce(receivedEvent, 100)
My attempt:
function debounce(func, timeInterval) {
return (args) => {
setTimeout(func, timeInterval)
}
}
function receivedEvent() {
console.log('receive')
}
receivedEvent();
receivedEvent();
receivedEvent();
But this still generates 3 outputs. I need it to only produce one output according to the requirements.
In your attempt you did not call debounce, but just called your own function receivedEvent. Maybe the site where your attempt is tested will do this for you, but we cannot know this from your question. Just make sure it is called.
To test the requirements you need to use a better use case: one based on a function that receives arguments. This is needed because you must prove that the debounced function is called after the timeout with the last passed arguments.
The key to this pattern is to use variables within a closure:
function debounce(func, timeInterval) {
let timer;
let lastArgs;
return (...args) => {
lastArgs = args; // update so we remember last used args
if (timer) return; // not ready yet to call function...
timer = setTimeout(() => {
func(...lastArgs);
timer = 0; // reset timer (to allow more calls...)
}, timeInterval);
}
}
function receivedEvent(arg) {
console.log('receive ' + arg)
}
receivedEvent = debounce(receivedEvent, 100)
receivedEvent("a");
receivedEvent("b");
receivedEvent("c");
// Output will be "c" after 100ms
Note that the question's definition of "debounce" deviates a bit from its usual definition, where the first invocation actually calls the function immediately, and only then starts the timeout (cooldown-period).
I have a set of about 100 arguments that all take different amounts of time to run through a given function. Each is a brief animation on a page, animating a different part depending on the argument, and they take about 1-3 seconds each.
I checked this: Nested setTimeout alternative?
...but it only works when the subfunctions take the same amount of time,
I can collect the arguments in an array in the order they should go, i.e.:
args= [arg1, arg2, arg3, arg4...]
Currently my calls looks like this:
setTimeout(myfunction(arg1), 3000);
setTimeout(myfunction(arg2), 5000);
setTimeout(myfunction(arg3), 7500);
setTimeout(myfunction(arg4), 8500);...
I'd really like to be able to have code that says "when myfunction(arg1) is finished, wait 500 milliseconds and then execute myfunction(arg2), then when that is finished wait 500 ms and execute func3, etc."
I don't know how to incorporate that into either the running of the setTimeouts or the definition of myfunction().
Thank you.
Promises are a perfect way to chain async operations.
If you could consider changing the body of myFunction so that it returns a promise then you could chain those operation easily.
The body of myFunction would look like this
function myFunction(args, time) {
return new Promise(function (resolve, reject) {
setTimeout(function () {
// here you do your stuff
resolve(); // resolve the promise when it's done
}, time);
})
}
And you call it this way
var args = [
{ args: "", timeout: 100 },
{ args: "", timeout: 300 }
]
var promise = Promise.resolve();
args.forEach(function (animation) {
promise = promise
.then(myFunction.bind(null, animation.args, animation.timeout))
// ^ chaining promise so that they fire one after another
})
You can just schedule your next task in the callback of the previous setTimeout, like that:
var tasks = [
{ arg : "arg1", delay : 3000},
{ arg : "arg2", delay: 2000},
{ arg : "arg3", delay : 2500}
];
function myFunction(arg) {
console.log(new Date(),arg);
}
function schedule() {
var task = tasks.shift();
if(task) {
setTimeout(function() {
myFunction(task.arg);
if(tasks.length) schedule();
},task.delay);
}
}
schedule();
This code will call myFunction("arg1") in 3000ms, then myFunction("arg2") in +2000ms and then myFunction("arg3") in +2500ms.
Each time it will remove (shift) the first element of your "task list",
and then stop once it is empty.
Take a note that this code will mutate your tasks array (by removing the next task from it on an each iteration), so you won't be able to reuse it.
If that is a problem, just use an explicit index to address the next task:
function schedule(tasks,i) {
if(i<tasks.length) {
setTimeout(function() {
myFunction(tasks[i].arg);
if(i+1<tasks.length) schedule(tasks,i+1);
},tasks[i].delay);
}
}
schedule(tasks,0);
I think the easiest way to sort out this problem is a promise chain:
var args = [1, 2, 3, 4, 5, 6]
var i = 0;
function doStuff(arg) {
//do stuff
console.log(arg)
}
function getPromise(cb, arg, time){
return function() {
return new Promise(function(resolve){
setTimeout(function(){
cb(arg)
resolve()
}, time)
})
}
}
var promise_chain = Promise.resolve();
while (args[i]) {
promise_chain = promise_chain.then(getPromise(doStuff, args[i++], 500))
}
This code will generate a bunch of promises. Each one waits 500ms to resolve itself and execute next bunch of code. Hope this help.
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')
}
I would like to create a delay function in javascript that takes a parameter of amount of time to delay, so that I could use it do introduce delay between execution of JavaScript lines in my QML application. It would perhaps look like this:
function delay(delayTime) {
// code to create delay
}
I need the body of the function delay(). Note that setTimeout() of JavaScript doesn't work in QML.
As suggested in the comments to your question, the Timer component is a good solution to this.
function Timer() {
return Qt.createQmlObject("import QtQuick 2.0; Timer {}", root);
}
timer = new Timer();
timer.interval = 1000;
timer.repeat = true;
timer.triggered.connect(function () {
print("I'm triggered once every second");
})
timer.start();
The above would be how I'm currently using it, and here's how I might have implemented the example in your question.
function delay(delayTime) {
timer = new Timer();
timer.interval = delayTime;
timer.repeat = false;
timer.start();
}
(Which doesn't do anything; read on)
Though the exact way you are looking for it to be implemented suggests that you are looking for it to block until the next line of your program executes. But this isn't a very good way to go about it as it would also block everything else in your program as JavaScript only runs in a single thread of execution.
An alternative is to pass a callback.
function delay(delayTime, cb) {
timer = new Timer();
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Which would allow you to use it as such.
delay(1000, function() {
print("I am called one second after I was started.");
});
Hope it helps!
Edit: The above assumes you're working in a separate JavaScript file that you later import into your QML file. To do the equivalent in a QML file directly, you can do this.
import QtQuick 2.0
Rectangle {
width: 800
height: 600
color: "brown"
Timer {
id: timer
}
function delay(delayTime, cb) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.start();
}
Rectangle {
id: rectangle
color: "yellow"
anchors.fill: parent
anchors.margins: 100
opacity: 0
Behavior on opacity {
NumberAnimation {
duration: 500
}
}
}
Component.onCompleted: {
print("I'm printed right away..")
delay(1000, function() {
print("And I'm printed after 1 second!")
rectangle.opacity = 1
})
}
}
I'm not convinced that this is the solution to your actual problem however; to delay an animation, you could use PauseAnimation.
Marcus' answer does the job, but there is one big problem.
The problem is that the callback keeps connected to triggered signal even after triggered once. This means that if you use that delay function again, the timer will triggers all callbacks connected before again. So you should disconnect the callback after triggered.
This is my enhanced version of the delay function:
Timer {
id: timer
function setTimeout(cb, delayTime) {
timer.interval = delayTime;
timer.repeat = false;
timer.triggered.connect(cb);
timer.triggered.connect(function release () {
timer.triggered.disconnect(cb); // This is important
timer.triggered.disconnect(release); // This is important as well
});
timer.start();
}
}
...
timer.setTimeout(function(){ console.log("triggered"); }, 1000);
Here's another variation which utilizes the Component object to house the Timer object.
Then we implement a setTimeout look-a-like function to dynamically create and invoke this Timer object.
N.B. The answer assumes Qt5.12.x which includes ECMAScript 7 (and therefore ECMAScript 6) to utilize parameter shortcuts, rest parameters and spread syntax:
function setTimeout(func, interval, ...params) {
return setTimeoutComponent.createObject(app, { func, interval, params} );
}
function clearTimeout(timerObj) {
timerObj.stop();
timerObj.destroy();
}
Component {
id: setTimeoutComponent
Timer {
property var func
property var params
running: true
repeat: false
onTriggered: {
func(...params);
destroy();
}
}
}
In the following snippet, we will invoke console.log(31), console.log(32), console.log(33) in a random time delay between 0-1000ms from now.
console.log("Started");
setTimeout(console.log, Math.floor(1000 * Math.random()), 31);
setTimeout(console.log, Math.floor(1000 * Math.random()), 32);
setTimeout(console.log, Math.floor(1000 * Math.random()), 33);
See also: https://community.esri.com/groups/appstudio/blog/2019/05/22/ecmascript-7-settimeout-and-arrow-functions
The answer from Bumsik Kim is great, this answer changes it slightly so that the timer can be used on a repeating basis and then stopped and reused when desired.
The QML for the timer to add where required.
// Allow outside access (optional)
property alias timer: timer
Timer {
id: timer
// Start the timer and execute the provided callback on every X milliseconds
function startTimer(callback, milliseconds) {
timer.interval = milliseconds;
timer.repeat = true;
timer.triggered.connect(callback);
timer.start();
}
// Stop the timer and unregister the callback
function stopTimer(callback) {
timer.stop();
timer.triggered.disconnect(callback);
}
}
This can be used as follows.
timer.startTimer(Foo, 1000); // Run Foo every 1 second
timer.stopTimer(Foo); // Stop running Foo
timer.startTimer(Bar, 2000); // Run Bar every 2 seconds
timer.stopTimer(Bar); // Stop running Bar
function Foo() {
console.log('Executed Foo');
}
function Bar() {
console.log('Executed Bar');
}
Here's my continued evolution of the prior answers https://stackoverflow.com/a/62051450/3220983 and https://stackoverflow.com/a/50224584/3220983...
Add this file / component to your project:
Scheduler.qml
import QtQuick 2.0
Timer {
id: timer
property var _cbFunc: null
property int _asyncTimeout: 250
// Execute the callback asynchonously (ommiting a specific delay time)
function async( cbFunc )
{ delay( cbFunc, _asyncTimeout ) }
// Start the timer and execute the provided callback ONCE after X ms
function delay( cbFunc, milliseconds )
{ _start( cbFunc, milliseconds, false ) }
// Start the timer and execute the provided callback repeatedly every X ms
function periodic( cbFunc, milliseconds )
{ _start( cbFunc, milliseconds, true ) }
function _start( cbFunc, milliseconds, isRepeat ) {
if( cbFunc === null ) return
cancel()
_cbFunc = cbFunc
timer.interval = milliseconds
timer.repeat = isRepeat
timer.triggered.connect( cbFunc )
timer.start()
}
// Stop the timer and unregister the cbFunc
function cancel() {
if( _cbFunc === null ) return
timer.stop()
timer.triggered.disconnect( _cbFunc )
_cbFunc = null
}
}
Then, implement in another component like:
...
Scheduler { id: scheduler; }
scheduler.delay( function(){ console.log('Delayed'); }, 3000 );
You can use anonymous functions like shown here, or else callback into named functions. Use the simple async to fire off code in a non-blocking manner, if you aren't too concerned about the exact timing. Note that while it's tempting to use a 0 ms timeout for an "asynchronous" callback (as one would with a C++ QTimer), that is not the right approach with a QML Timer! These timers don't appear to queue events on an event loop where screen redraws are given priority. So, if your goal is to defer a given operation to achieve "instant" UI changes first, you need to dial up the delay interval as shown here. Using 0ms will often cause the code to fire prior to redraws.
Note that one of these "Scheduler" instances can only be bound to one callback function, on one given interval, at a time. Multiple instances are required if you need to "overlap" delayed events.
you can use QtTest
import QtTest 1.0
import QtQuick 2.9
ApplicationWindow{
id: window
TestEvent {
id: test
}
function delay_ms(delay_time) {
test.mouseClick(window, 0, 0, Qt.NoButton, Qt.NoModifier, delay_time)
}
}
This should be sufficient:
void QmlUtils::singleShot(int msec, QJSValue callback)
{
QTimer::singleShot(msec, this, [callback] () mutable {
if (callback.isCallable())
callback.call();
});
}
then call it in QML, wherever you are:
qmlUtils.singleShot(5000, () => console.log("Hello!"))
Done.
If you want, you can use this without even writing it. Simply expose it to QML with:
ctx->setContextProperty("lqtUtils", new lqt::QmlUtils(qApp));
I have a code which needs to be executed after some delay say 5000 ms.Currently I am using setTimeout but it is asynchronous and i want the execution to wait for its return. I have tried using the following:
function pauseComp(ms)
{
var curr = new Date().getTime();
ms += curr;
while (curr < ms) {
curr = new Date().getTime();
}
}
But the code i want to delay is drawing some objects using raphaeljs and the display is not at all smooth. I am trying to use doTimeout plugin. I need to have a delay only once as the delay and code to be delayed are both in a loop. I have no requirement for a id so I am not using it.
For example:
for(i; i<5; i++){ $.doTimeout(5000,function(){
alert('hi'); return false;}, true);}
This waits for 5 sec befor giving first Hi and then successive loop iterations show alert immediately after the first. What I want it to do is wait 5 sec give alert again wait and then give alert and so on.
Any hints/ suggestions are appreciated!
Variation on the accepted answer which is just as good as this one.
Also, I agree with the caveats of preferring setTimeout and asynchronous function calling but sometimes e.g., when building tests, you just need a synchronous wait command...
function wait(ms) {
var start = Date.now(),
now = start;
while (now - start < ms) {
now = Date.now();
}
}
if you want it in seconds, divide start ms by 1000 on the while check...
=== EDIT ===
I noticed that my answer has bubbled to the top but it really shouldn't be the top answer. That was written as an alternative in case you cannot use async / await in your code or you're waiting for a trivial amount of time (like a second or two for testing).
The top answer should note that the async/await pattern is a much better way of doing this and will significantly use less energy and CPU cycles.
See #michaelolof 's answer below for example....
const wait = (msec) => new Promise((resolve, _) => {
setTimeout(resolve, msec));
});
(async () => {
console.log("Start...")
await wait(5000);
console.log("...End")
})();
If you'd like to take advantage of the new async/await syntax, You can convert set timeout to a promise and then await it.
function wait(ms) {
return new Promise((resolve, reject) => {
setTimeout(() => {
console.log("Done waiting");
resolve(ms)
}, ms )
})
}
(async function Main() {
console.log("Starting...")
await wait(5000);
console.log("Ended!")
})();
Synchronous wait (only for testing!):
const syncWait = ms => {
const end = Date.now() + ms
while (Date.now() < end) continue
}
Usage:
console.log('one')
syncWait(5000)
console.log('two')
Asynchronous wait:
const asyncWait = ms => new Promise(resolve => setTimeout(resolve, ms))
Usage:
(async () => {
console.log('one')
await asyncWait(5000)
console.log('two')
})()
Alternative (asynchronous):
const delayedCall = (array, ms) =>
array.forEach((func, index) => setTimeout(func, index * ms))
Usage:
delayedCall([
() => console.log('one'),
() => console.log('two'),
() => console.log('three'),
], 5000)
Using the new Atomics API, you can start synchronous delays without performance spikes:
const sleep = milliseconds => Atomics.wait(new Int32Array(new SharedArrayBuffer(4)), 0, 0, milliseconds)
sleep(5000) // Sleep for 5 seconds
console.log("Executed after 5 seconds!")
JavaScript is a single-threaded language. You cannot combine setTimeout and synchronous processing. What will happen is, the timer will lapse, but then the JS engine will wait to process the results until the current script completes.
If you want synchronous methods, just call the method directly!
If you want to process something after the setTimeout, include it or call it from the timeout function.
Non-timeout loops (that check the time or count to 1000000 or whatever) just lock up the browser. setTimeout (or the $.doTimeout plugin) is the best way to do it.
Creating timeouts within a loop won't work because the loop doesn't wait for the previous timeout to occur before continuing, as you've discovered. Try something more like this:
// Generic function to execute a callback a given number
// of times with a given delay between each execution
function timeoutLoop(fn, reps, delay) {
if (reps > 0)
setTimeout(function() {
fn();
timeoutLoop(fn, reps-1, delay);
}, delay);
}
// pass your function as callback
timeoutLoop(function() { alert("Hi"); },
5,
5000);
(I just cobbled this together quickly, so although I'm confident that it works it could be improved in several ways, e.g., within the "loop" it could pass an index value into the callback function so that your own code knows which iteration it is up to. But hopefully it will get you started.)
I have made a simple synchronous timeout function. It works in two different ways, callback and non-callback.
function:
function wait(ms, cb) {
var waitDateOne = new Date();
while ((new Date()) - waitDateOne <= ms) {
//Nothing
}
if (cb) {
eval(cb);
}
}
callback example:
wait(5000,"doSomething();");
non-callback example:
console.log("Instant!");
wait(5000);
console.log("5 second delay");
JavaScript is single-threaded
It is impossible to make a synchronous delay in javascript, simply because JavaScript is a single-threaded language. The browser (most common JS runtime environment) has what's called the event loop. So everything that the browser does happens in this very loop. And when you execute a script in the browser, what happens is:
The event loop calls your script
Executes it line by line
Once the script has finished*, the event loop continues running
Notice that all of this is happening during a single frame of the event loop! And that means that no other operation (like rendering, checking for user input, etc.) can happen before the script has exited. (*) The exception is async JavaScript, like setTimeout/Interval() or requestAnimationFrame() which are not run on the main thread. So from event loops prespective, the script has finished running.
This implies that if there were a synchronous delay in JavaScript, the whole browser would have to wait for the delay to finish, and meanwhile it's unable to do anything. So there is no, and there won't be any synchronous delay in JS.
Alternative - Maybe?
The alternative depends on the actual thing you want to do. In my case, I have a requestAnimationFrame() loop. So all I needed to do was to store the time, and check between the old time and new time in the loop.
let timer =
{
startTime: 0,
time: 1000, // time for the counter in milliseconds
restart: true // at the beginning, in order to set startTime
};
loop();
function loop()
{
if(timer.restart === true)
{
timer.startTime = Date.now();
timer.restart = false;
}
if((Date.now() - timer.startTime) >= timer.time)
{
timer.restart = true;
console.log('Message is shown every second');
// here put your logic
}
requestAnimationFrame(loop);
}
Here's how you can use the JQuery doTimeout plugin
jQuery('selector').doTimeout( [ id, ] delay, callback [, arg ... ] );
From the docs: "If the callback returns true, the doTimeout loop will execute again, after the delay, creating a polling loop until the callback returns a non-true value."
var start = Date.now();
console.log("start: ", Date.now() - start);
var i = 0;
$.doTimeout('myLoop', 5000, function() {
console.log(i+1, Date.now() - start);
++i;
return i == 5 ? false : true;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery-dotimeout/1.0/jquery.ba-dotimeout.min.js"></script>
Node solution
Use fs.existsSync() to delay
const fs = require('fs');
const uuidv4 = require('uuid/v4');
/**
* Tie up execution for at-least the given number of millis. This is not efficient.
* #param millis Min number of millis to wait
*/
function sleepSync(millis) {
if (millis <= 0) return;
const proceedAt = Date.now() + millis;
while (Date.now() < proceedAt) fs.existsSync(uuidv4());
}
fs.existsSync(uuidv4()) is intended to do a few things:
Occupy the thread by generating a uuid and looking for a non-existent file
New uuid each time defeats the file system cache
Looking for a file is likely an optimised operation that should allow other activity to continue (i.e. not pin the CPU)
Inspired by #andrew65952 but more modern-like and faster
function wait(ms) {
const now = Date.now()
while (Date.now() - now <= ms) { /* do nothing */}
}
Solution using function generators. To show that it can be done. Not recommended.
function wait(miliseconds){
const gen = function * (){
const end = Date.now() + miliseconds;
while(Date.now() < end){yield};
return;
}
const iter = gen();
while(iter.next().done === false);
}
console.log("done 0");
wait(1000);
console.log("done 1");
wait(2000);
console.log("done 2");