This question already has answers here:
What is the JavaScript version of sleep()?
(91 answers)
Closed 2 years ago.
I'm trying to create something like slide show that is moved automatically after a delay.
I don't really understand how promises work so I find myself unable to create the sleep functinon.
Any solutions?
const startBtn = document.querySelector('.startBtn');
const box = document.querySelector('.box')
startBtn.addEventListener('click', () => {
for(var i = 1; i <= 20;i++){
//sleep(60000); <= the problem
box.style.transform = 'translateY(' + (-i * 100) + 'vh)';
}
});
Easiest you can do is use setTimeout:
setTimeout(function(){ alert("Hello"); }, 3000);
See: https://www.w3schools.com/jsref/met_win_settimeout.asp
Maybe you'll want to consider setInterval instead for your problem. In both cases you have to rework your solution a bit, the for loop won't help you much.
function sleep(delay){
return new Promise(resolve=>{
setTimeout(resolve,delay);
})
}
const fn = async () =>{
let pre = new Date()
console.log(pre);
await sleep(2000);
let after = new Date();
console.log(after - pre);
}
startBtn.addEventListener('click', async() => {
for(var i = 1; i <= 20;i++){
// sleep i*1000 seconds
await sleep(i* 1000);
box.style.transform = 'translateY(' + (-i * 100) + 'vh)';
}
});
Related
I've been bashing my head against this wall I am completely new to JavaScript coming from c#
and I am completely baffled for my class I have to smooth out a simple code we made to count down from zero by making it into a loop and for the life of me I just cant get it to work
var i = 10;
var timeout = 10000;
var x = 10
if (i == 5) {
alert("help me")
}
while (i > 0) {
//10
setTimeout(() => {
document.getElementById("counter").innerHTML = i;
i = i - 1;
}, timeout);
timeout = timeout - 1000;
}
Asynchrony in JavaScript is a rather involved subject.
Traditional loops (for, while, do..while, for..of) are synchronous, and so cannot help you reach your goal here.
To do what you want, you can use indirect recursion like so:
const countdown = (from = 10, to = 0, interval = 1000, cb = console.log) => {
if(from < 0) return
cb(from)
setTimeout(() =>
countdown(--from), interval)
}
countdown()
There is also a more modern approach that enables the use of syntax that looks a bit more familiar. This approach uses for await... of, the syntax for which does not appear to be supported by StackOverflow's transpiler:
const delay = (interval) => new Promise((resolve) =>
setTimeout(resolve, interval))
async function* countdown(from = 10, to = 0, interval = 1000) {
for(;from >= 0; from--) {
yield from
await delay(interval)
}
}
for await(let count of countdown()) {
console.log(count)
}
setInterval is what you're looking for to execute a function every certain amount of time:
let i = 10;
let interval = setInterval(function() {
document.getElementById("counter").innerHTML = i;
i--;
if(i < 0) clearInterval(interval);//Clear the interval when complete
}, 1000);//Every 1000 ms = every second
The code below will countdown to zero.
var i = 10;
while (i > 0){
i--;
console.log(i);
}
I'm trying to print one letter after another but this code just waits 100ms and then prints the value with no pauses. Any idea why this happens and how to fix it?
Code:
for (let i = 0; i < welcText.length; i++) {
setTimeout(()=>{
welcome.innerText += welcText[i];
},100);
}
Note that setTimeout does not actually delay the running of the code that comes after; it just schedules for something to happen in the future. So all the letters are added at the same time, after 100 milliseconds.
The most straightforward way to fix it is to make each subsequent timeout wait a bit longer, by multiplying the delay with the index of the letter (i * 100):
const welcome = document.getElementById('welcome');
const welcText = 'Welcome!';
for (let i = 0; i < welcText.length; i++) {
setTimeout(() => {
welcome.innerText += welcText[i];
}, i * 100);
}
<div id="welcome"></div>
The following function divtxt() returns a Promise. You can use it to send a txt to a div with a given id and let each letter appear in ms intervals. AND: you can build a chain of any number of follow-up actions with it:
function divtxt(id, txt, ms, wait = 0) {
const div = document.getElementById(id);
return new Promise((res, rej) => {
setTimeout(() => { // optional initial timeout, when wait>0
div.textContent = "";
const a = txt.split(""),
iv = setInterval(() => {
if (a.length)
div.textContent += a.shift();
else {
clearInterval(iv);
res(txt);
}
}, ms);
}, wait);
});
}
divtxt("welcome", "Hello world, this is my way of doing it! 🤩", 100)
.then(prevText => (console.log(prevText + ' is done.'),
divtxt("descr", "You can also chain this function with any number of consecutive actions."
+" Now: wait for 2 seconds ...", 100)))
.then(() => divtxt("welcome", "This promised-based approach REALLY lets you do it!! 👍🏻", 50, 2000))
.then(() => (console.log("ready?"),"Yes! I am REALLY DONE now! 😁"))
.then(console.log)
#welcome {
font-weight: 900
}
<div id="welcome"></div>
<div id="descr"></div>
You can do it using setInterval instead, and using an iterator to call the next char of the string every time. This is a bit more complicated, but has the advantage of not having multiple schedulers running if the string is too long. See the working example below.
const welcome = document.getElementById('welcome');
const welcomeText = 'Welcome!';
// returns a function that returns the next char in the string everytime its called
function createIterator(string) {
let currentIndex = 0;
return function() {
return string[currentIndex++];
}
}
// initializes the iterator with the text
let welcomeIterator = createIterator(welcomeText);
let welcomeInterval = setInterval(function() {
let nextChar = welcomeIterator();
// if we finish the string we clear the interval
if (!nextChar) {
return clearInterval(welcomeInterval);
}
// if the char exists, we append it to the div
welcome.innerText += nextChar;
}, 100);
<div id="welcome"></div>
you can do it like this also
const welcText = 'Welcome!';
let i = 0;
const interval = setInterval(() => {
if (i >= welcText.length) {
clearInterval(interval);
} else {
document.getElementById('helloword').innerHTML += welcText[i];
i++;
}
}, 100);
<h1 id="helloword"></h1>
Hello I need help on my code. I am not really familiar with Promises. I created a function called EmitRandomNumber(). In this function, after 2 full seconds (2000 ms), it generates a random number between 0 to 100. If the random number generated is below 80, I need to call that function again, up to 10 times, until the random number generated is greater than 80.
let attempt = 1;
let rN;
function EmitRandomNumber() {
return new Promise((resolve, reject)=> {
console.log(`Attempt #${attempt}. EmitRandomNumber is called.`);
setTimeout(()=>{
let randomNumber = Math.floor(Math.random() * 100) + 1;
rN = randomNumber;
console.log("2 seconds have passed.");
if(randomNumber>=80&&attempt<=10){
console.log(randomNumber,attempt);
resolve();
}else if(randomNumber<80&&attempt<=10){
attempt++;
console.log(`Random number generated is ${randomNumber}.`);
console.log("===============================");
EmitRandomNumber();
}
},2000);
});
}
let promise = EmitRandomNumber();
promise.then(()=>{
console.log(`Random number generated is ${rN}!!!!`);
console.log("===============================");
}).catch(()=>{
console.log("End");
});
I dont know if I am using the promise properly and sometimes when it is above 80 it doesnt execute whatever code is in the resolve. Can you help me how I can fix my code. Thank you!
So the code is mostly good, you just did not specify when to 'reject' the promise. From what you described you want this to 'reject' (or display console.log('End')) IF the promise does not find a number after 10 attempts. So you only needed to add a condition (if attempt===10) etc.
EDIT: The resolve and reject need to be returned.
let attempt = 1;
let rN;
function EmitRandomNumber() {
return new Promise((resolve, reject)=> {
console.log(`Attempt #${attempt}. EmitRandomNumber is called.`);
setTimeout(()=>{
let randomNumber = Math.floor(Math.random() * 100) + 1;
rN = randomNumber;
console.log("2 seconds have passed.");
if(randomNumber>=80&&attempt<=10){
console.log(randomNumber,attempt);
return resolve();
}else if(randomNumber<80&&attempt<=10){
attempt++;
console.log(`Random number generated is ${randomNumber}.`);
console.log("===============================");
EmitRandomNumber();
//CHECK FOR CONDITION NUMBER OF ATTEMPTS
} else if(attempt>10){
return reject();
}
},2000);
});
}
let promise = EmitRandomNumber();
promise.then(()=>{
console.log(`Random number generated is ${rN}!!!!`);
console.log("===============================");
}).catch(()=>{
console.log("End");
});
It may be easier to read and reason about using async functions and await. E.g.:
const MAX_TRIES = 10;
const sleep = (ms) => {
return new Promise(resolve => setTimeout(resolve, ms));
}
const getRandomNumber = () => {
return Math.floor(Math.random() * 100) + 1;
}
const getNumberWaitAndReturn = async () => {
let rN = getRandomNumber();
let attempt = 1;
while (rN < 80 && attempt <= MAX_TRIES) {
await sleep(2000);
rN = getRandomNumber();
attempt += 1;
}
if (attempt > MAX_TRIES) {
console.log(attempt)
throw new Error("No luck! It took more than 10 tries!")
}
return {
rN,
attempt
}
}
const result = getNumberWaitAndReturn().then(v => {
console.log(v)
});
You doing pretty good, you just need a little more practice to do it better, I highly recommend you start using closure instead of declaring global variables as you are doing into your code.
Before tell you how you can solve this, I will tell you that are the error, your function will only work as you expect if the first time its executed it generates a random number above of 80, otherwise the function will never be resolved, why ? that's because everytime you are calling the EmitRandomNumber() into the function itself you are creating a new Promise reference so the first one that you created is never handled because you create a new reference promise, so the new reference, it's no handle because your are calling inside the function itself and nobody is doing .then(...).
So how to solve this ? First at all you need to create a closure to create this.
const emitRandomNumber = () => {
const MAX_ATTEMPTS = 10;
const MS_START_TIME = 2000;
const MINIMUM_NUMBER = 80;
const MAXIMUM_NUMBER = 100;
let attempts = 0;
const randomNumber = (max) => Math.floor(Math.random() * max);
return new Promise((resolve, reject) => {
const startRandomNumber = () => {
attempts++;
const number = randomNumber(MAXIMUM_NUMBER);
if (number < MINIMUM_NUMBER && attempts <= MAX_ATTEMPTS) {
return setTimeout(startRandomNumber, MS_START_TIME);
}
if (number < MINIMUM_NUMBER && attempts > MAX_ATTEMPTS) {
return reject();
}
resolve(number);
};
setTimeout(startRandomNumber, MS_START_TIME);
});
}
As you can see we are using closure to create function inside function body, so the only function that we call again it's the startRandomNumber function, so this won't generate new promise instances, instead we are keeping the same promise reference and we just execute the random number function until we reach the attempts.
This question already has answers here:
What does var mean in Javascript? [closed]
(2 answers)
Closed 2 years ago.
<script>
var start;
function shapeAppear() {
document.getElementById("shapes").style.display = "block";
var start = new Date().getTime();
}
function delay() {
setTimeout(shapeAppear,Math.random() *2000);
}
delay();
document.getElementById("shapes").onclick = function() {
document.getElementById("shapes").style.display = "none";
var position = Math.floor(Math.random() * 500);
document.getElementById("shapes").style.left = position + "px";
document.getElementById("shapes").style.right = position + "px";
document.getElementById("shapes").style.top = position + "px";
document.getElementById("shapes").style.bottom = position + "px";
var end = new Date().getTime();
var time = end - start;
time /= 1000;
document.getElementById("time").innerHTML = time + "s";
delay();
}
</script>
Here in this code i want the date() function to return a specific integer value.
Because when we subtract the two Date() functions we must get the integer value.
It is a scoping issue. if you use var inside a function, that variable will only exist in the scope of that function.
So what you could do is this:
var start;
function shapeAppear() {
start = new Date().getTime();
}
By removing var in the shapeAppear function, you're updating the var that is created outside the function.
Besides that as Rodney mentioned you call delay before shapeAppear which means that start is not defined when calling delay.
Hope that makes sense.
This question already has answers here:
How do I add a delay in a JavaScript loop?
(32 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
I want to make a timer using while, and when I lunch the code in Chrome, the Chrome don't load.
I am making this:
var time = 0;
while (time < 5) {
setTimeout(function(){
tempo[0].innerHTML = time;
time++;
}, 1000);
}
I expect when time it gets to 5, javascript will exit the loop and execute the next action
You should use async and await
var time = 0;
var result = document.querySelector('#display')
async function start(){
while (time < 5) {
await new Promise(res => {
setTimeout(function(){
result.innerHTML = time;
time++;
res();
}, 1000);
})
}
}
start()
<div id="display"></div>