I've encountered a problem that's driving me crazy for like 10 days now... Basically i have a function that fire (the handleText) and I want to wait the end of that function before running a second one (the handleBackground).
I've tried deferred and promises but I think I don't understand them well because I can't get it to work the way I want.
function handleText(){
//BLAST INIT
var blastedwords = $('.baselineHeader').blast({
delimiter: 'word',
});
//SHUFFLE ORDER IN ARRAY
blastedwords = shuffleAds( blastedwords);
function shuffleAds(arr){
for(var j, x, i = arr.length; i; j = parseInt(Math.random() * i), x = arr[--i], arr[i] = arr[j], arr[j] = x);
return arr;
}
//ADD CLASS TO SPAN CREATED WITH BLAST WITH A RANDOM DELAY
blastedwords.each(function(index) {
var min = 45, max = 100;
var delay = Math.floor(Math.random() * (max - min) + min);
var that = $(this);
var t = setTimeout(function() {
$(that).addClass("test");
}, delay * index);
});
}
function handleBackground(){
$('.baselineHeader').addClass('processed');
}
handleText();
handleBackground();
Right now, handleText start, and handleBackground (my second function that I want to run after the first one is finished) fire at the same time and doesn't wait for handleText to finish.
I want handleText to run and wait for the each loop to give class to every span created with blast.js before running handleBackground.
Can someone help me with this ?
Have a great day folks :)
I'd recommend setting up a global variable totalTime which you can use to add up the inidivual delays. That way you can use another setTimeout to call the function handleBackground() after totalTime has passed.
var totalTime = 0;
blastedwords.each(function(index) {
var min = 45,
max = 100;
var delay = Math.floor(Math.random() * (max - min) + min) * index;
totalTime += delay;
var that = $(this);
var t = setTimeout(function() {
$(that).addClass("test");
}, delay);
});
setTimeout(handleBackground, totalTime);
Define delay outside of your function and each iteration increase the delay so that the next one is a random amout of time after the last one.
var delay = 0;
blastedwords.each(function(index) {
var min = 45, max = 100;
delay += Math.floor(Math.random() * (max - min) + min);
var that = $(this);
var t = setTimeout(function() {
$(that).addClass("test");
}, delay * index);
});
Related
I'm trying to iterate over a string array with a delay of a few milliseconds every step of iteration. Something like below -
var l = ['a', 'b', 'c'];
var delay = 5000;
for(var i = 0;i < l.lenght;i++) {
document.querySelectorAll("a[title='" + l[i] + "']")[0].parentNode.children[0].click();
delay = 5000 + Math.floor(Math.random() * 5000) + 1;
**<WAIT for 'delay' number of milliseconds**
}
I've been able to convert the code to below using setTimeout() method -
var i = 0;
var interval = setInterval(function() {
if (i < l.length) {
document.querySelectorAll("a[title='" + l[i] + "']")[0].parentNode.children[0].click();
i++;
}
else {
clearInterval(interval);
}
//delay = 5000 + Math.floor(Math.random() * 5000) + 1); **NOT SURE where to change the delay variable**
}, delay);
But the delay variable essentially becomes a constant once setTimeout kicks off. How to change the delay variable in each iteration?
You can make a recursive timer function for this:
Try the following :
function displayValue(){
let arr = ['a', 'b', 'c'];
let delay = 1000;
let i = 0;
function timerFunction(i){
if(i === arr.length)
return;
setTimeout(()=>{
console.log(arr[i]);
i++;
timerFunction(i);
}, delay);
delay = delay + 1000 + Math.floor(Math.random() * 4000);
}
timerFunction(i);
}
displayValue();
Could you try replacing that delay variable with a function such as this?
var i = 0;
var interval = setInterval(
function() {
if (i < l.length) {
document.querySelectorAll("a[title='" + l[i] + "']")[0].parentNode.children[0].click();
i++;
}
else {
clearInterval(interval);
}
},
function() {
return 5000 + Math.floor(Math.random() * 5000) + 1;
}
);
setInterval, which you have used in your example, initializes a callback launching every (circa) N ms, where N is fixed. You have to clear it later on with clearInterval.
setTimeout on the other hand means - invoke my callback after ~N time. You could then call another setTimeout inside the callback, with a different N.
as an example:
function callback() {
/*
your logic here
*/
delay = 5000 + Math.floor(Math.random() * 5000) + 1);
setTimeout(callback, delay); // for your "clearInterval" case - just don't invoke this
}
setTimeout(callback, initialDelay);
This thread appears the closest I found to the fundamental question of how to iterate through an array at a random time interval, which isn't as easy as one would think.
Although arguably a little general for the specific question asked, the currently accepted answer looks the closest match to the fundamental question. The code below is a minor modification which looks to provide a random delay on the first pass and logs each random delay after the logging each array value.
function displayValue(){
let arr = ['a', 'b', 'c','d', 'e'];
let delay = Math.floor(Math.random()*10000);
let i = 0;
function timerFunction(i){
if(i === arr.length)
return;
setTimeout(()=>{
console.log(arr[i]);
console.log(`delay was ${Math.floor(delay/1000)} seconds`);
i++;
timerFunction(i);
}, delay);
delay = Math.floor(Math.random()*10000);
}
timerFunction(i);
}
displayValue();
The value of the above modification probably depends on the context.
Interestingly, applying the introduction to forEach from bootcamp provides an alternate solution which is probably closer related to the OP!
var colors = ["red", "green", "blue", "yellow"];
function printArr(x){
var random = Math.round(Math.random()*60000);
setTimeout(() => {
console.log(x);
console.log(`Delay was ${Math.floor(random/1000)} seconds`)
}, random);
};
colors.forEach(printArr);
So I have this javascript which basically goes from 0 to 1000 at the same exact speed:
HTML:
<div id="value">0</div>
Javascript:
function animateValue(id, start, end, duration) {
if (start === end) return;
var range = end - start;
var current = start;
var increment = end > start? 1000 : +1;
var stepTime = Math.abs(Math.floor(duration / range));
var obj = document.getElementById(id);
var timer = setInterval(function() {
current += increment;
obj.innerHTML = current;
if (current == end) {
clearInterval(timer);
}
}, stepTime);
}
animateValue("value", 100, 25, 5000);
Basically I want the counter to go up with random speed intervals.
So as it goes up, it will slow down and speed up completely random until it reaches 1000.
How do I achieve that?
Thanks for your help.
I don`t understand purpose of duration parameter in function. That is why i used it as a max duration of one iteration.
/**
* Increment value with random intervals.
* #param {string} id - Id of DOM Element.
* #param {number} start - Start counter value. Applied immediately.
* #param {number} end - End counter value.
* #duration {number} duration - Max duration of one iteration in ms.
*/
function animateValue(id, start, end, duration) {
let current = start;
const obj = document.getElementById(id);
obj.innerHTML = current; // immediately apply start value
const setIncrOut = () => {
let time = Math.random() * duration;
setTimeout(function () {
if (current < end) {
current += 1;
obj.innerHTML = current;
setIncrOut(time);
}
}, time);
}
setIncrOut();
}
animateValue("value", 100, 1001, 1000);
<div id="value"></div>
A simplified version:
animate(document.querySelector(`#value`), 5, 50, 1000);
function animate(elem, start, end, maxDuration) {
elem = elem || document.querySelector(`#value`);
if (start < end) {
elem.textContent = !elem.textContent.trim() ? start : start + 1;
return setTimeout( () =>
animate( elem, start + 1, end, maxDuration ),
Math.floor( (Math.random() * maxDuration) ) );
}
}
#value {
font-size: 2rem;
font-weight: bold;
}
<div id="value"></div>
Instead of using setInterval, which has a static pause between iterations you could create your own asynchronous loop that pauses with variable time.
Incomplete, but something like...
async function setVaryingInterval(callback, start, end, increment) {
var step = start;
while (step != end) {
step += increment;
var random = Math.random() * 3000;
await new Promise(resolve => setTimeout(resolve, random));
callback(step);
}
}
setVaryingInterval((value) => {
// this will be executed with random delays, and the delay can be changed by adding logic to the "random" variable
console.log(value);
}, 0, 1000, 1);
You will need to add logic for speeding up / slowing down, this will simply have a random delay between every interval, but should be easy enough to add if you have a vision on how it should behave.
You can paste this code in your dev tools (F12) and see the random behaviour, and tailor it to your needs.
I have a function called ajaxCall() which simple does the call on a server and returns a value from a feed.
What I wanted to do is to save the value from feed to firstInterval variable, wait 10 seconds, make the call again and save the value to secondInterval variable. And then animate the increasing of these numbers on the webpage. This is what we have so far:
setInterval(function(){
getAmounts()
}, 11000);
function getAmounts(){
firstInterval = ajaxCall();
setTimeout(() => {
secondInterval = ajaxCall();
animateValue('#bronze-price p', firstInterval, secondInterval, 10000)
}, 10000);
};
function animateValue(id, start, end, duration) {
start = parseInt(start);
end = parseInt(end);
var range = end - start;
var current = start;
var increment = end > start? 1 : -1;
var stepTime = Math.abs(Math.floor(duration / range));
var obj = document.querySelector(id);
var timer = setInterval(function() {
current += increment;
obj.innerHTML = current;
if (current == end) {
clearInterval(timer);
}
}, stepTime);
}
So the idea is to have a function which gets first interval, after 10 seconds it grabs the second interval and calls the animation. This all is wrapped into setInterval function so I could change the number smoothly repeatedly.
However I am pretty sure that thats not a very clean solution since its setInterval in setTimeout and this all is wrapped in another setInterval function. I am also getting this kind of warnings in the console with both functions:
[Violation] 'setInterval' handler took ms
What would be the best approach to follow up on this idea but optimize the code?
I think Promises and requestAnimationFrame makes this a lot easier to handle while also getting rid of setTimeout/setInterval. An example would be:
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math/random#Getting_a_random_integer_between_two_values_inclusive
function getRandomIntInclusive(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min + 1)) + min;
}
// fake api endpoint
const ajaxCall = () => new Promise(resolve => {
setTimeout(resolve, 400, 1000 + getRandomIntInclusive(0, 1000));
});
// simple animation helper using requestAnimationFrame
const animate = (from, to, duration, cb) => {
const start = performance.now();
return new Promise(resolve => {
requestAnimationFrame(function loop() {
const f = (performance.now() - start) / duration;
cb(from + Math.round(f * (to - from)));
f < 1.0
? requestAnimationFrame(loop)
: resolve();
});
});
};
// main
(async (interval) => {
// where to output
const dst = document.querySelector('#out');
// initial value
let prev = 0;
// wait for next value of ajaxCall
while (true) {
const next = await ajaxCall();
console.log(`animating: ${prev} -> ${next}`);
// animate from `prev` to `next`
await animate(prev, next, interval, current => {
dst.innerHTML = current;
});
prev = next;
}
})(10000);
<div id="out"></div>
I am generating a random number on click in jQuery. At the end of this post, you can see the code that I am working with.
Is there a way where every time a new random number gets generated it gets added to the old one in a variable called totalRandomNumbers?
I want to do it for all three variables random, random_0, random_1.
$("#reset").click(function(){
var random = Math.floor(Math.random() * 12);
var random_0 = Math.floor(Math.random() * 12);
var random_1 = Math.floor(Math.random() * 12);
$("#push0").html(random);
$("#push1").html(random_0);
$("#push2").html(random_1);
$('input[name="hamPush"]').val($("#push0").html());
$('input[name="zikPush"]').val($("#push1").html());
$('input[name="musPush"]').val($("#push2").html());
})
At the start of your JavaScript, make a variable:
var totalRandomNumbers = 0;
And when you generate your random number, add it to the variable.
totalRandomNumbers += (code to generate random number)
var randomSum = 0;
function getRandomInt(min, max) {
min = Math.ceil(min);
max = Math.floor(max);
return Math.floor(Math.random() * (max - min)) + min;
};
function sumRandom() {
randomSum += getRandomInt(1, 100)
};
$('.genRandomButton').on('click', function() {
console.log(randomSum)
}
Just tried in browser console:
var _totalRandomNumbers = 0;
Object.defineProperty(window, "totalRandomNumbers", {
get: function() { return _totalRandomNumbers += Math.random(); }
});
console.log(totalRandomNumbers);
console.log(totalRandomNumbers);
and so on :-)
You can do anything in get accessor, store old values etc.
My goal is to perform a jQuery script that'll make any number visually grow from zero until its value with setInterval().
Here's what I came up with:
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var refresh = 5;
var start = 0;
var step = 1;
var interval = window.setInterval(function() {
start += step;
$el.text(start);
if(start >= max)
clearInterval(interval);
}, refresh);
});
My problem is I have numbers ranging from a few hundreds to several hundreds thousands. With this script, bigger number take more time to reach their value.
My goal is to make any number, regardless of its goal value, take the same amount of time to reach it. I sense that I should divide the number by the number of seconds I want the animation to run and then, set the result as the interval step?
I'm inquiring but still seeking for help :)
Thanks.
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var duration = 1000; // shared duration of all elements' animation
var refresh = 5;
var frames = duration / refresh; // number of frames (steps)
var start = 0;
var step = Math.max(Math.round(max / frames), 1); // step should be >= 1
var interval = window.setInterval(function() {
if(start + step < max) {
start += step;
}
else {
start = max;
clearInterval(interval);
}
$el.text(start);
}, refresh);
});
This should work I suppose,
$('.grow').each(function() {
var $el = $(this);
var max = parseInt($el.text().replace(/\s/g, ''));
var start = 0;
var refresh = 5;
var totalSteps = 10;
var step = max/totalSteps;
function calculate(){
start += step;
$el.text(Math.round(start));
if(start < max){
setTimeout(function() {
calculate();
}, refresh);
}
}
calculate();
});
This will always finish in 100 steps. I.e. 100*refresh = 100*5 = 500 seconds.