Need help timing events with jquery - javascript

Here's my code:
tripper = 2;
$("#topheader").mousewheel(function(event, delta) {
if (tripper == 2){
startPlace = $("#content").scrollLeft();
startCounter = something;
tripper = 1;
} else {
currentPlace = $("#content").scrollLeft();
if(startCounter < 100){ // milliseconds
distanceMoved = currentPlace - startPlace;
if(distanceMoved > 100){
slideRight();
} else if(distanceMoved < -100){
slideLeft();
}
} else {
tripper = 2;
}
}
}
What is the proper way to check if 100 milliseconds has passed sense the first time through this function? In the 5th line of code i have the variable "something" which needs to be replaced with a counter of some sort. Or maybe I'm going about this in an entirely wrong way. Suggestions?

You can instantiate a "Date" object like this:
var then = new Date();
Later you can make another one:
var now = new Date();
Subtraction gives the difference in milliseconds:
var elapsed = now - then;
(The coercion from "Date" to "Number" is implicit when the two date values appear on either side of the subtraction operator. The conversion is just like calling "now.getTime()".)

The following code it is untested but basically, after 100 milliseconds, it should reset timeout back to null and ultimately set tripper back to 2;
tripper = 2;
timeout = null;
$("#topheader").mousewheel(function(event, delta) {
if (tripper == 2){
startPlace = $("#content").scrollLeft();
if (!timeout) {
setTimeout(function() {
timeout = null
}, 100);
}
tripper = 1;
} else {
currentPlace = $("#content").scrollLeft();
if(timeout){ // milliseconds
distanceMoved = currentPlace - startPlace;
if(distanceMoved > 100){
slideRight();
} else if(distanceMoved < -100){
slideLeft();
}
} else {
tripper = 2;
}
}
}

Related

clearTimeout(timer) not taken into account - New timer variable created each time

In the current slideshow I'm building, I use a timer variable to rotate the slides automatically every 4s. Since manual controls are also present, I wanted to reset this timer whenever the controls are used to avoid any premature succession between two slides, but didn't manage to do it.
I supposed it to be a scope problem, but the timer variable is out of the functions that are trying to share it (showSlide(n) and changeSlide(n)). Yet a brand new timer variable seems to be created each time the changeSlide function is called : the slides automatic rotation quickens each time the "next" control is used, as if multiple timeouts were calling the function simultaneously. What is wrong here ?
const slideshows = document.getElementsByClassName("js-slideshow");
[].forEach.call(slideshows, function(slideshow) {
slideshowlize(slideshow);
});
function slideshowlize(slideshow){
const desc = slideshow.getElementsByClassName("js-desc");
const slide = slideshow.getElementsByClassName("js-slide");
let timer;
let index = 0;
const slidePrev = slideshow.querySelector('.js-prev');
const slideNext = slideshow.querySelector('.js-next');
function showSlide(n){
clearTimeout(timer); // This one is not used yet
if(n < 0){
n = slide.length -1;
}
else if(n > slide.length -1){
n = 0;
}
let i;
for(i = 0; i < slide.length; i++){
slide[i].classList.remove("is-shown");
}
for(i = 0; i < desc.length; i++){
desc[i].classList.remove("is-shown");
}
slide[n].classList.add("is-shown");
desc[n].classList.add("is-shown");
index = n;
timer = setTimeout(function(){
changeSlide(1);
}, 4000);
}
function changeSlide(n){ // this is where the magic doesn't happen
clearTimeout(timer);
if (n > 0){
showSlide(index += 1);
} else {
showSlide(index -= 1);
}
timer = setTimeout(function(){
changeSlide(1);
}, 4000);
}
showSlide(index);
slidePrev.addEventListener('click', function(){
changeSlide(-1);
});
slideNext.addEventListener('click', function(){
changeSlide(1);
});
}
Edit : Two different timers were set up. Since showSlide(n) were already resetting the timer, changeSlide(n) had no need to do it too. Thanks to Bergi for pointing it out.
function changeSlide(n){
//removed "clearTimeout(timer);"
if (n > 0){
showSlide(index += 1);
} else {
showSlide(index -= 1);
}
//removed "timer = setTimeout(...);"
}

How would you throttle a recursive function?

Let's suppose I want to run a recursive function that will take weeks, months or even years to complete. It returns all possible permutations of a string based on the specified parameters. While it's running, I want to be able to see how far along it is progressing - e.g. how many permutations it has generated so far. In a nutshell, I want a very long-running recursive function to execute without locking up my UI.
Also, I would like to do this with vanilla ES5, not in strict mode, and without WebWorkers. It should be able to run in IE9.
What I have works fine as-is, but when I raise numspaces to 10, for example, the browser locks up. So I am assuming that I am just working the browser too hard, and "throttling" the amount of work it has to do would help solve this problem. I did try increasing the setTimeout delays from 1 to 250 and even 1000, but the browser still locked up.
I am interested in this simply because I tried to do it, and couldn't. Also, I know for a fact that this code is terribly inefficient and there are much, much better ways to do what I am looking to achieve. So recommend them!
var inputString = "abcdefghijklmnopqrstuvwxyz";
function allPossibleCombinations(input, length, curstr, callback) {
if (curstr.length === length) return callback(curstr);
(function(n) {
setTimeout(allPossibleCombinations.bind(n, input, length, curstr + input[n], callback), 1);
n++;
if (n < input.length) setTimeout(arguments.callee.bind(n,n), 1);
})(0);
}
var totalResults = 0,
numDigits = inputString.length,
numSpaces = 2,
maxResults = Math.pow(numDigits, numSpaces),
consoleElement = document.getElementById('console'),
startTime = +new Date();
console.log("Starting.. expecting", maxResults, "total results...");
allPossibleCombinations(inputString.split(""), numSpaces, "", function(result) {
totalResults++;
if (totalResults === maxResults) {
var elapsed = +new Date() - startTime;
consoleElement.innerText = "Done.";
console.log("Completed in", elapsed, "ms!");
} else {
// Do something with this permutation...
//...
// Show progress...
var progress = ((totalResults / maxResults) * 100).toFixed(2) * 1;
consoleElement.innerText = progress + "%";
}
});
<div id="console"></div>
You’re getting close with the setTimeout, but the current implementation queues up all the timers for a given prefix at once, resulting in an exponential number of timers and quick memory exhaustion. One small change would be to create another callback to indicate completion and use it to wait on recursive calls, never holding more than one timer at once:
var inputString = "abcdefghijklmnopqrstuvwxyz";
function allPossibleCombinations(input, length, curstr, resultCallback, doneCallback) {
if (curstr.length === length) {
resultCallback(curstr);
doneCallback();
return;
}
var n = 0;
(function next() {
if (n === input.length) {
doneCallback();
return;
}
allPossibleCombinations(
input, length, curstr + input[n],
resultCallback,
function () {
n++;
setTimeout(next, 0);
});
})();
}
var totalResults = 0,
numDigits = inputString.length,
numSpaces = 4,
maxResults = Math.pow(numDigits, numSpaces),
consoleElement = document.getElementById('console'),
startTime = +new Date();
console.log("Starting.. expecting", maxResults, "total results...");
allPossibleCombinations(
inputString.split(""), numSpaces, "",
function (result) {
totalResults++;
// Do something with this permutation...
//...
// Show progress...
var progress = ((totalResults / maxResults) * 100).toFixed(2) * 1;
consoleElement.innerText = progress + "%";
},
function () {
var elapsed = +new Date() - startTime;
consoleElement.innerText = "Done.";
console.log("Completed in", elapsed, "ms!");
});
<div id="console"></div>
That’s really slow, though. Thinking of how you could write this as a generator:
function* strings(input, length, current) {
if (current.length === length) {
yield current;
return;
}
for (let i = 0; i < input.length; i++) {
yield* strings(input, length, current + input[i]);
}
}
and translating that to a system where the callback is responsible for resuming generation:
function strings(input, length, current, yield_, continue_) {
if (current.length === length) {
yield_(current, continue_);
return;
}
var i = 0;
(function next() {
if (i === input.length) {
continue_();
return;
}
strings(input, length, current + input[i++], yield_, next);
})();
}
you can have the flexibility of setting a timer as infrequently as you’d like for performance.
"use strict";
function countSequences(n, k) {
var result = 1;
for (var i = 0; i < k; i++) {
result *= n--;
}
return result;
}
function strings(input, length, current, yield_, continue_) {
if (current.length === length) {
yield_(current, continue_);
return;
}
var i = 0;
(function next() {
if (i === input.length) {
continue_();
return;
}
var c = input[i++];
strings(input.replace(c, ''), length, current + c, yield_, next);
})();
}
var inputString = "abcdefghijklmnopqrstuvwxyz";
var totalResults = 0;
var numDigits = inputString.length;
var numSpaces = 5;
var maxResults = countSequences(numDigits, numSpaces);
var consoleElement = document.getElementById('console');
var startTime = +new Date();
console.log("Starting… expecting", maxResults, "total results.");
strings(
inputString, numSpaces, "",
function (result, continue_) {
if (totalResults++ % 1000 === 0) {
var progress = (totalResults / maxResults * 100).toFixed(2);
consoleElement.innerText = progress + "% (" + result + ")";
setTimeout(continue_, 0);
} else {
continue_();
}
},
function () {
var elapsed = +new Date() - startTime;
consoleElement.innerText = "Done.";
console.log("Completed in", elapsed, "ms!");
});
<div id="console"></div>
(This style is still non-optimal, but it’ll never finish for 2610 no matter how quick individual operations are.)

Replacing previous number in JS/JQuery

I would like to add an effect that some websites now have i.e. coffees drank: and then number of coffees drank, gradually growing from 0 to N-1. This is my attempt, if I print i in the console in the first if statement , each number prints out. But, when in HTML it goes from 0-950 instantly with no numbers in between.
To sum make it up: I would like the number to increment on the page, each new number replacing its previous number.
for (i = 0; i < 950; i++) {
if ($("#counter").length) {
setTimeout(function() {
// body...
$("#counter").append('<p id = "counter">' + i + '</p>');
}, 2000);
console.log(i);
} else {
$(".coffee-drank").append('<p id = "counter">' + i + '</p>');
}
}
If I got your idea correctly, it can be done generally like this:
var start = -1, end = 950;
var countUp = function func() {
if(start >= end) return;
var elem = document.getElementById("counter");
elem.innerText = ++start;
setTimeout(func, 25);
}
countUp();
count up to 950:
<span id="counter">0</span>
UPDATE
In your case it might look like this (no need for a cycle at all):
var start = -1, end = 950;
var countUp = function func() {
if(start >= end) {
// the end is reached; start is equal to 950 now; do something useful and quit
$(".coffee-drank").append('<p id = "counter">' + start +'</p>');
return;
}
$("#counter").text(++start);
setTimeout(func, 25);
}
countUp();
Replace your for loop with this:
var speed = 16; // Lower is faster
increase(0, 950);
function increase(i, max){
if(i <= max){
if ($("#counter").length) {
$("#counter").html(i);
} else {
$(".coffee-drank").append('<p id = "counter">' + i + '</p>');
}
setTimeout(function(){
increase(++i, max);
}, speed);
}
}

10ms Interval with firefox

So I made a simple timer in a format like this: MM:SS.MS
You can view it here [removed]
It works fine in chrome, IE, etc. but in Firefox the seconds are like twice as long..
I took a look at some other stopwatches, but I don't quit understand them.
Whats the best way to do it ? Right now I have a 10ms interval which generates the timer.
The function looks like that, I hope it's understandable:
var state = false;
var msTimer = null;
var min = document.getElementById("min");
var sec = document.getElementById("sec");
var ms = document.getElementById("ms");
var minCount = 0;
var secCount = 0;
var msCount = 0;
document.onkeydown = function timer(e) {
if (!e) { e = window.event; }
if (e.keyCode == "32") {
if (state == false) {
state = true;
min.innerHTML = "00";
sec.innerHTML = "00";
ms.innerHTML = "00";
msTimer = window.setInterval(function() {
if (msCount == 99) {
msCount = 0;
secCount++;
// Minutes
if (secCount == 60) {
secCount = 0;
minCount++;
if (minCount <= 9)
{ min.innerHTML = "0" + minCount; }
else
{ min.innerHTML = minCount; }
}
// Seconds
if (secCount <= 9)
{ sec.innerHTML = "0" + secCount; }
else
{ sec.innerHTML = secCount; }
} else { msCount++; }
// Miliseconds
if (msCount <= 9)
{ ms.innerHTML = "0" + msCount; }
else
{ ms.innerHTML = msCount; }
// 1 Hour
if (minCount == 60) {
clearInterval(msTimer);
min.innerHTML = "N0";
sec.innerHTML = "00";
ms.innerHTML = "0B";
state = false;
minCount = 0;
secCount = 0;
msCount = 0;
}
}, 10);
} else if (state == true) {
state = false;
clearInterval(msTimer);
minCount = 0;
secCount = 0;
msCount = 0;
}
}
Thanks for any advices :)
Edit:
And btw, it's much smoother in firefox, if I remove all styles from the timer.
But that can't be the solution..
You shouldn't be relying on the interval of the timer being exactly 10ms. It would be better if you viewed each timer tick as a request to refresh the on-screen timer, but take the measurements from the system clock or something like that.
Then however slow or busy the machine (and JS implementation) is, you'll always see an accurate timer1 - just one which updates less often.
1 This will only be as accurate as the system clock, of course. If Javascript has access to a high-performance timer like .NET's Stopwatch class or Java's System.nanoTime() method, that would be better to use.
Timing in Javascript is not guaranteed. A 10ms interval will only ever be approximately 10ms, most likely it will be delayed a tiny bit each time. The correct way to do a timer in Javascript is to save a starting timestamp upon starting the timer, then each 10ms or so calculate the difference between the starting timestamp and the current time and update an element on the page with the formatted value.

Javascript - making 2 setInterval() be synchronous

I have 2 functions calling setInterval but I need them to be synchronous. Here is my code(yes, they are really simple).
var number1 = 0;
function caller(){
go();
come();
}
function go() {
anim1 = setInterval("doActionGo()", 20);
}
function come() {
anim2 = setInterval("doActionCome()", 20);
}
function doActionGo(){
if(number1 < 1023) {
number1++;
} else {
clearInterval(anim1);
}
}
function doActionCome() {
if (number1 > 0) {
number1 = number1 - 1
} else {
clearInterval(anim2);
}
functions doActionGo() and doActionCome() would be any code. Does anybody know how to solve it?
Regards!
To execute two animations in sequence just start the second one at the end of the first... for example:
var anim1, anim2;
var number = 0;
function animation1()
{
number = number + 1;
if (number > 1000)
{
clearInterval(anim1);
anim2 = setInterval(animation2, 20);
}
}
function animation2()
{
number = number - 1;
if (number < 0)
{
clearInterval(anim2);
}
}
function start()
{
anim1 = setInterval(animation1, 20);
}
Here is way to call them in sequence:
var number1 = 0;
function caller(){
go( come );
}
function go(comeFn) {
var anim = setInterval(function(){
if(number1 < 100) {
number1++;
} else {
clearInterval(anim);
comeFn();
}
}, 20);
}
function come() {
var anim = setInterval(function(){
if (number1 > 0) {
number1--;
} else {
clearInterval(anim);
}
}, 20);
}
And two comments:
you shouldn't use strings in setInterval('functionName', 30) but directly functions
if you don't use anim1 instead of var anim1 it is considered as a global variables
See demo of the following →
It wasn't really clear what you were asking, but it inspired me to write this mini animation queue. Maybe you or someone else will benefit from it:
var number1 = 0,
number2 = 1023,
queue = [];
// execute every XX miliseconds
function tick(delay) {
// iterate through queue
for (var i = 0, il = queue.length; i < il; i++) {
if (queue[i]) {
// execute each tick function
queue[i].tick();
}
}
// recall tick
setTimeout(function() {
tick(delay);
}, delay);
}
// kill tick function of matching name
function qKill(name) {
for (var i = 0, il = queue.length; i < il; i++) {
if (queue[i]) {
if (queue[i].name === name) {
queue.splice(i, 1);
}
}
}
}
var go = {
name: 'go',
tick: function() {
if (number1 < number2) {
number1++;
// do whatever here
} else {
qKill('go');
}
}
};
var come = {
name: 'come',
tick: function() {
if (number2 > number1) {
number2 = number2 - 1;
// do whatever here
} else {
qKill('come');
}
}
};
queue.push(go);
queue.push(come);
tick(20);
Demo →
As people already commented, JavaScript is single threaded. So running two functions simultaneously is impossible. However a couple of strategies can be used to simulate this.
For GUI effects, interpolation can be used. Basically, a single function is responsible of transitioning things step by step by interpolating the start and end value(be it an opacity, a position, a variable, a state or whatever can be interpolated). A javascript library can use this simple concept to create effects for example.
A second approach is to use co-routines available in javascript since version 1.7. This article (although a little old) describes how to simulate threading in javascript and can be a good starting point to understand the mechanism involved in a co-routine powered design.
Hope this will help :)

Categories