A
A
Abr_ya2019-02-18 08:16:31
JavaScript
Abr_ya, 2019-02-18 08:16:31

Is it possible to use setTimeout recursively?

I'm trying to write a smooth scrolling function in pure JS. Clicking on the button scrolls to the "catalog" element. At some point, this is what happened:

function scrollToStep(coord = 0, step = 20, temp = 1000) {
        if (coord > step) {
            setTimeout(function() {
                window.scrollBy(0, step);
            }, temp);
            coord -= step;
            console.log(coord);
            scrollToStep(coord, step, temp)
        } else {
            return false;
        }
    }

    buttonChoice.addEventListener('click', function() {
        let catalog = document.querySelector('.catalog');
        scrollToStep(catalog.getBoundingClientRect().top);
    });

I was expecting that once a second it would be displayed in the console for the interval by which it remains to shift and a shift by the specified step occurs.
Instead: all gaps are displayed at once, and the shift occurs abruptly after one second.
Hence the question: can setTimeout be used recursively? If so, please point me in the right direction! If not - advise another tool, please!

Answer the question

In order to leave comments, you need to log in

3 answer(s)
S
Sergey Sokolov, 2019-02-18
@Abr_ya

Move the following call into the body of a function that will execute after a pause:

function scrollToStep(coord = 0, step = 20, pause = 1000) {
  if (coord > step) {
    setTimeout(function() {
      coord -= step;
      window.scrollBy(0, step);
      scrollToStep(coord, step, pause)
    }, pause);
  } else {
    return false;
  }
}

buttonChoice.addEventListener('click', function() {
  let catalog = document.querySelector('.catalog');
  scrollToStep(catalog.getBoundingClientRect().top);
});

P
profesor08, 2019-02-18
@profesor08

You can use it recursively. But if you want smooth animations, timeouts are not the way to go. You need requestAnimationFrame, and the calculation is there, smoothness is guaranteed. Using the ease function, you can achieve all sorts of scrolling behavior, from nice and smooth, to rubbery, jumpy and funny.
Examples of common functions:
https://gist.github.com/gre/1650294
Demo:
https://jsfiddle.net/profesor08/h7fmcs35/

let currentScrollY = 0;
let targetScrollY = 0;
let t = 0;

document.body.addEventListener("click", () => {
  targetScrollY = Math.floor(Math.random() * getScrollheight());
  currentScrollY = getScrollTop();
  t = 0;
});

function getScrollheight() {
  return document.documentElement.scrollHeight || document.body.scrollHeight;
}

function getScrollTop() {
  return document.documentElement.scrollTop || document.body.scrollTop;
}

function setScrollTop(to) {
  document.documentElement.scrollTop = to;
  document.body.scrollTop = to;
}

function ease(t) { return (--t)*t*t+1 }
  

function animate() { 
  if (t < 1) {
    t += 0.01;
  
  	setScrollTop(
    	currentScrollY + (targetScrollY - currentScrollY) * ease(t)
    );
  }
    
  requestAnimationFrame(animate);
}
  
animate();

A
Abr_ya, 2019-02-18
@Abr_ya

Interesting behavior of a fixed feature found in Firefox!
It alternately scrolls down by 20 or 40 pixels, and therefore scrolls the page lower than it should!

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question