Add Timeout / Sleep function inside javascript loop - javascript

I'm trying to add a sleep / delay function inside a js file, This one:
var webTest = function()
{
let regex = /^https?:\/\//;
let url = $('#list_urls').val().split('\n');
var xmlhttp = [], i;
var myObj2 = [], i;
for(let i = 0; i < url.length; i++)
{
(function(i) {
xmlhttp[i] = new XMLHttpRequest();
url[i] = url[i].replace(regex, '');
xmlhttp[i].open("GET", "https://website.com/API?key=<MY_API_KEY>&url="+url[i], false);
xmlhttp[i].onreadystatechange = function() {
if (xmlhttp[i].readyState === 4 && xmlhttp[i].status === 200) {
myObj2 = JSON.parse(xmlhttp[i].responseText);
document.getElementById("demo"+i).innerHTML = myObj2.results[1].categories;
}
};
xmlhttp[i].send();
})(i);
console.log(`The Server2: `+ myObj2);
}
}
I want this script to pause for 10 second and then again do work and then again pause for 10 second and do like this untill text length is greater thatn i in loop! My code works if i run for single time but it doesn't works if i run in loop because the website has rate limit in the api so that's why i'm trying to add a sleep function.
So what i've tried is await sleep(); method and also tried setTimeout method but it's not working as expected in sort it doesn't works at all with my code!
await sleep(); just doesn't works at all and displays msg like
Uncaught SyntaxError: await is only valid in async functions and async generators webTestfile.js:27

You can make use of ES6's async/await-feature!
To use await, it needs to be in a function/expression body declared async.
Basically, this will make your function be asynchronous, and make it wait for a Promise to be fulfilled. We make that Promise be fulfilled after a set delay using setTimeout().
Note that "after a set delay" does not mean "exactly after", it basically means "as early as possible after".
By doing this, the asynchronous function waits for the promise to be fulfilled, freeing up the callstack in the meantime so that other code can be executed.
The order of execution of this example is (simplified) as follows:
sleepingFunc() is placed on callstack
In iteration: await for Promise to be fulfilled, suspending this call 🡒 freeing up callstack
Place new calls on callstack
Eventually, Promise is fulfilled, ending await 🡒 place suspended call back on callstack
Repeat until sleepingFunc() finished
As you can see in step 3, if other calls take up more time than the delay, the suspended call will have to wait that extra time longer.
function sleep(ms) {
return new Promise(resolveFunc => setTimeout(resolveFunc, ms));
}
async function sleepingFunc() {
for (let i = 0; i < 5; ++i) {
console.log(i + " - from sleep");
await sleep(1000);
}
}
function synchronousFunc() {
for (let i = 0; i < 5; ++i) {
console.log(i + " - from sync");
}
}
sleepingFunc();
synchronousFunc();

This runs snippet runs one task every 1 second until the condition is satisfied, and then clears the timer.
const work = (i)=>{
console.log('doing work here ', i);
}
let counter = 0
const timer = setInterval(()=>{
if (timer && ++counter >= 10) {
clearInterval(timer)
}
work(counter);
}, 1000)

Related

How can setTimeout run in order

I have two for loop, inside them I have setTimeout function like following code:
for(let i=0;i<3;i++){
setTimeout(()=>{console.log(i)}, 1000)
}
for(let i=0;i<3;i++){
setTimeout(()=>{console.log(i)}, 1000)
}
i want the second loop does not executed until after the first loop finished,
I want this result:
0
1
2
0
1
2
- and between 2 numbers wait 1 second.
how i can do that?
I can't comment yet or I would ask clarifying questions so I'll give you what I think you're asking for. If you want a 1 second delay between each number being logged to the console then this will work:
const func = async () => {
for (let i = 0; i < 3; i++) {
await new Promise((resolve) =>
setTimeout(() => {
console.log(i);
resolve();
}, 1000)
);
}
for (let i = 0; i < 3; i++) {
await new Promise((resolve) =>
setTimeout(() => {
console.log(i);
resolve();
}, 1000)
);
}
};
func();
A quick rundown of what's happening here. I created an outer function named func which I made asynchronous so that I can use the await keyword within it. I then put the setTimeout call inside a new instance of Promise. The promise combined with the await means that javascript will essentially stop at that line until the Promise calls resolve. Once resolve is called that instance of Promise is finished and the await statement stops "blocking" javascript and the callbackque continues.
TLDR:
To use await you must be in an asynchronous function.
If await is used in front of a Promise everything will stop until the promise resolves.
Placing the resolve of the promise inside the callback given to setTimeout ensures that we will wait until each timeout finishes BEFORE the next timeout begins.
This will work
nxt (0, 0);//seed the stack
function nxt(num, itertn){
if(num == 3){//want till 2
if(itertn == 0){// first or 2nd iteration
num =0;
itertn++;
}else{
return;//after 2nd stop
}
}
console.log(num);//the work
num++;
setTimeout(nxt, 1000, num, itertn);//next after a second
}
But there are other ways to do this
I think that you're trying to do sort of a counter
Try something like this:
for(let i=1;i<=3;i++){
setTimeout(()=>{ console.log(i)}, i*1000 )
}
Let me know if this solve your problem
Try nested loop
for(let i=0;i<2;i++){
for(let j=0;j<3;j++){
setTimeout(()=>{console.log(j)}, 1000)
}
}
One solution is create promises, and with map and promise.all, you can group each loop of promises and execute them sequentially.
(async () => {
const second = (i) => new Promise(resolve => setTimeout(() => {
console.log(i)
resolve(i)
}, 1000))
const loop = () => Array(3).fill(0).map(async(item, index) => {
return await second(index)
})
var startTime = performance.now()
await Promise.all(loop())
var endTime = performance.now()
console.log(endTime - startTime)
await Promise.all(loop())
endTime = performance.now()
console.log(endTime - startTime)
})()

Get result of currently running async function

How to check if there is already running function and if it is exist listen to this function result;
async function a() {
// wait 5 seconds and return foo = foo + 1;
// if A is already running await and return result of this running function A instead result;
}
If I translate the problem correctly, A returns a promise that is asynchronously settled. While the promise is pending, all calls to a wrapper function around A should return the currently pending promise.
If, however, A has not been called, or a previously return promise has been settled, A should be called again.
This can be achieved by chaining off the promise returned by A, using promise handlers to determine results are no longer pending, and have the wrapper function return the chained promise. This example code speeds up the process a little - four successive calls made to a 500ms apart get the same fulfilled value from A which is taking 2000ms to perform a mythical asynchronous task:
// promise a delay
const delay = ms => new Promise(resolve=>setTimeout(resolve, ms));
// async function A
let foo =0;
async function A() {
await delay( 2000); // 2 second example
return foo = foo + 1;
}
// Wrapper function a
const a=(()=>{
let pending = null;
const onfulfill = data => { pending = null; return data};
const onreject = err => { pending = null; throw err};
let a = ()=> pending || (pending = A().then(onfulfill, onreject));
return a;
})();
// and test
async function test() {
for( let i=1; i < 11; ++i) {
a().then( data=> console.log(`a() call ${i} fulfills with ${data}`));
await delay(500);
}
}
console.log(" a is a named function ", a.name == 'a')
test();
a is coded to be a named function which minimizes run time object creation by using the two parameter form of then and passing pre-compiled functions as handler arguments.
The catch handler re-throws the error for caller code to handle.
synchronous and asynchronous code don't mix well together. Calls to wrapper function a always receive a pending promise value in return.
Solution
You can create class that will be execute one flow (maximum) and await result if flow already running. It may looks something like that:
class OneThreadExecutor {
// Boolean variable which represents is task running right now
taskRunning = false;
// All Promise.resolve callbacks
listeners = [];
// Accept initial value
constructor(value = 0) {
this.value = value;
}
// Send [result = value + 1] after 5 sec
startNewTask = () => {
this.taskRunning = true;
setTimeout(() => {
this.taskRunning = false;
return this.sendResult();
}, 5000)
}
// Call all Promise.resolve callbacks, and pass [value + 1] to them
sendResult = () => {
for (const listener of this.listeners) {
listener(++this.value);
}
this.listeners = [];
}
// Main method that exec one task
getResult = () => new Promise(resolve => {
// Add callback to queue
this.listeners.push(resolve);
// Start new task if necessary
if (!this.taskRunning) this.startNewTask();
})
}
General concept
Async getResult method will register promise in class' queue. Any successfull task execution will send result to queue. Current task returns value + 1 on each getResult call and take 5 seconds for whole flow.
Usage
const a = new OneThreadExecutor(); // value = 0 by default
// will start task#1, 5 sec left till .then call, value = 1
a.getResult().then(...)
// 2.5 sec left, task#1 is already half progress, value = 2
setTimeout(() => {
a.getResult().then(...)
}, 2500)
Async/await
const a = new OneThreadExecutor(3); // let's set value = 3 initially
// will start task#1, 5 sec left till .then call, value = 4
a.getResult();
// wait till task#1 completed, 5 sec left, value = 5
const value = await a.getResult();
// will start task#2 bacause not task running, 5 sec left, value = 6
a.getResult();
Cons
In demo solution we already expect successful task execution, without error handling, so you may need to extend it for proper error catching during task execution.
var is_a_running = false;
function a() {
if (is_a_running == false) {
is_a_running = true
//do something
//after you have done the thing
is_a_running = false
}
else if (is_a_running == true){
result();
}
}
This is should help you

sleep functionality in browser/node js

Having a list of number [n1,n2...] I want to print the number then sleep for t1, t2 print(n2) sleep for t2 etc.
I manage to "remember" the scope but the problem is that it waits always 1 second only.
also when i hardcode a larger value eg 2000 it just prints all the numbers.
With promises:
function sleep(ms) {
return(
new Promise(function(resolve, reject) {
setTimeout(function() { resolve(); }, ms);
});
);
}
for (let i = 1; i <= 100; i++) {
sleep(i*1000).then(function() {
console.log(i);
});
}
with setTimeout same result
for (let i = 1; i <= 100; i++) {
(function(z) {
setTimeout(
function(){console.log(z);},
z*1000
);
})(i);
}
for (let i = 1; i <= 100; i++) {
(function(z){
setTimeout(
function(){console.log(z);},
z*1000
);
})(i);
}
That is because you start all your Promises and setTimeouts()s simultaniously, their time will run out basically at the same time.
I see two solutions to your problem:
You could wait until a Promise runs out before continuing your code
You could add the delay of the previous setTimeout() to the next one's delay
Both solutions run asynchronously, which would free up the callstack for other tasks (which is important to do since JavaScript runs single-threaded). The first solution however is more elegant, and keeps your code more readable. That is why I will only go more in-depth into the first one.
For 1. to work, you need to wrap your code (or at least the asynchronous part) in an asynchronous body to be able to use the await keyword. We will use the await keyword in combination with a Promise and setTimeout() just like you used it, but we will wait for the Promise to be resolved.
In code, this could look like this:
Note: That wrapped function expression, which is immediately invoked, is called an IIFE.
function sleep(ms) {
return new Promise(res => setTimeout(res, ms));
}
(async function() {
for (let i = 1; i <= 100; i++) {
console.log(i);
await sleep(i*1000);
}
})();

setTimeout in Node.js loop

I'm a bit confused as to how setTimeout works. I'm trying to have a setTimeout in a loop, so that the loop iterations are, say, 1s apart.
Each loop iteration makes an HTTP request and it seems like the server on the other end can't handle that many requests in such a short time span.
for (var i = 1; i<=2000 && ok; i++) {
var options = {
host:'www.host.com',
path:'/path/'+i
};
setTimeout(makeRequest(options, i), 1000);
};
Why does this not work and how can I achieve this?
Thank you
setTimeout is non blocking, it is asynchronous. You give it a callback and when the delay is over, your callback is called.
Here are some implementations:
Using recursion
You can use a recursive call in the setTimeout callback.
function waitAndDo(times) {
if(times < 1) {
return;
}
setTimeout(function() {
// Do something here
console.log('Doing a request');
waitAndDo(times-1);
}, 1000);
}
Here is how to use your function:
waitAndDo(2000); // Do it 2000 times
About stack overflow errors: setTimeout clear the call stack (see this question) so you don't have to worry about stack overflow on setTimeout recursive calls.
Using generators (io.js, ES6)
If you are already using io.js (the "next" Node.js that uses ES6) you can solve your problem without recursion with an elegant solution:
function* waitAndDo(times) {
for(var i=0; i<times; i++) {
// Sleep
yield function(callback) {
setTimeout(callback, 1000);
}
// Do something here
console.log('Doing a request');
}
}
Here is how to use your function (with co):
var co = require('co');
co(function* () {
yield waitAndDo(10);
});
BTW: This is really using a loop ;)
Generator functions documentation.
You need something like this
var counter = 5;
function makeRequst(options, i) {
// do your request here
}
function myFunction() {
alert(counter);
// create options object here
//var options = {
// host:'www.host.com',
// path:'/path/'+counter
//};
//makeRequest(options, counter);
counter--;
if (counter > 0) {
setTimeout(myFunction, 1000);
}
}
See also this fiddle
At the point of the alert(count); you can do your call to the server.
Note that the counter works opposite (counting down). I updated with some
comments where to do your thing.
Right now you're scheduling all of your requests to happen at the same time, just a second after the script runs. You'll need to do something like the following:
var numRequests = 2000,
cur = 1;
function scheduleRequest() {
if (cur > numRequests) return;
makeRequest({
host: 'www.host.com',
path: '/path/' + cur
}, cur);
cur++;
setTimeout(scheduleRequest, 1000)
}
Note that each subsequent request is only scheduled after the current one completes.
I might be late at the party but here is another (more readable) solution without the need to omit for loop.
What your code does is creating 2000 (actually 1999) setTimeout objects that will call the makeRequest function after 1 second from now. See, none of them knows about the existence of the other setTimeouts.
If you want them 1 sec apart from each other, you are responsible for creating them so.
This can be achieve by using your counter (in this case i) and the timeout delay.
for (var i = 1; i<=2000 && ok; i++) {
var options = {
host:'www.host.com',
path:'/path/'+i
};
setTimeout(makeRequest(options, i), i * 1000); //Note i * 1000
};
The first timeout object will be set for 1 second from now and the second one will be set for 2 seconds from now and so on; Meaning 1 second apart from each other.
I'm surprised that no one has mentioned this above, but it sounds like you need setInterval not setTimeout.
vat poller = setInterval(makeRequestFunc, 3000)
The code above will make a request every 3 seconds. Since you saved the object to the variable poller, you can stop polling by clearing the object like so:
cleanInterval(poller)
You're calling makeRequest() in your setTimeout call - you should be passing the function to setTimeout, not calling it, so something like
setTimeout(makeRequest, 1000);
without the ()
let i = 20;
let p = Promise.resolve(i)
while (i > 0) {
(i => {
p = p.then(() => {
return new Promise(function (resolve, reject) {
setTimeout(function () {
console.log(i);
resolve()
}, 2000)
})
})
})(i)
i--
}
p = p.then(data => console.log('execution ends'))
I'm very late on the subject (as usual ...;) but the only way I found to loop requests to a slow time response API and getting responses without HTTP 504 is using promises.
async function LoadDataFromAPI(myParametersArray) {
for(var i = 0; i < myParametersArray.length; i++) {
var x = await RunOneRequest(myParametersArray[i]);
console.log(x); // ok
}
}
The function called by the async function :
function RunOneRequest(parameter) {
return new Promise(resolve => {
setTimeout(() => {
request(parameter, (error, response, body) => {
// your request
});
resolve('ok);
}, 2000); // 2 secs
});
}

Synchronous delay in code execution

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");

Categories

Resources