sleep functionality in browser/node js - javascript

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);
}
})();

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)
})()

JS: Unsure of when to use Promise.resolve() vs returning a new Promise

I am unsure how the usage of returning a new Promise vs using a Promise.resolve() and want to make sure my understanding of these are correct.
Given these 3 functions below:
function testFunc() {
return Promise.resolve().then(() => {
//anything asynchronous in here has now become synchronous and
//execution of result of the function happens after this??
let i = 0;
while (i < 10000) {
console.log(i);
i++;
}
});
}
------
function testFunc2() {
return new Promise((resolve, reject) => {
//anything asynchronous in here is still asynchronous but the
//`resolve()` is then synchronous??
let i = 0;
while (i < 10000) {
if (i === 999) { resolve('I am a test func') };
i++;
}
})
}
------
//synchronous function
function logMe() {
let i = 0;
while (i < 10000) {
console.log("INSIDE LOG ME);
i++;
}
}
The way I understand it is that testFunc() immediately resolves the Promise and anything within there becomes synchronous. So if you were to execute:
testFunc();
logMe();
testFunc() would fully execute before logMe() was reached and executed.
For the testFunc2(), if it were executed in this order:
testFunc2();
logMe();
I understand it as the logic inside, in this case the while loop, would still execute synchronously and delay the execution of the following function, logMe(), but the resolve would be treated asynchronously.
It’s not that easy. You would have to use test Func.then(logMe()). Another option would be to run both functions in an asynchronous function:
async function run() {
await testFunc();
logMe();
}
The await is pretty simple - it runs the function and waits for it to finish, then runs the next lines. async is just there so that await can work (await does not work outside of async functions).
I prefer async/await, but many more prefer .then. It’s just what you want to use, both are very similar.
If I understand correctly what you're trying to achieve, you want to asynchronously execute operation inside the loop.
function testFunc2() {
const promises = []
for(let i = 0; i<1000; i++){
promises.push(new Promise((resolve) => {
console.log(i);
resolve()
}));
}
return Promise.all(promises);
}
function logMe() {
let i = 0;
while (i < 5) {
console.log("INSIDE LOG ME");
i++;
}
}
(async() => {
await testFunc2()
logMe();
})();

Add Timeout / Sleep function inside javascript loop

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)

How to ensure the execution order of a random number of promises?

How can I rearrange the code below to output 0011223344 instead of 01234<random values>? I'm relatively new to promises and don't know how to batch the promises in a way that the second one only executes when the first one is resolved.
function getPromise(value) {
return new Promise(function(resolve, reject) {
console.log(value);
setTimeout(function () {
resolve(value);
}, Math.random() * 1000);
});
}
for (var i = 0; i < 5; i++) {
getPromise(i).then(console.log);
}
EDIT
In the real scenario the number of promises is random and unpredictable.
Since promises inner code start to being executed immediately after creation, I can't have something like a promises array to iterate over, for example.
I guess that's the reason because I couldn't make it work with Promise.all.
Await the previous one, then execute the next:
var promise = Promise.resolve();
for (let i = 0; i < 5; i++) {
promise = promise.then( _=> getPromise(i).then(console.log) );
}

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

Categories

Resources