본문 바로가기

Javascript

Javascript: Animation 백그라운드 동작 중지 # requestAnimationFrame

728x90
반응형

Javascript로 무한슬라이드를 구현하는 과정에서

setInterval()을 사용했습니다

브라우저를 켜놓고 보면 아주 작동이 잘합니다.

그런데 다른 브라우저 탭을 열어놓고 다시 들어가보니 다음과 같은 상황이 발생...

 

setInterval()함수를 통해 불려진 콜백이 계속 쌓여있다가 브라우저로 다시 돌아오는 순간 한번에 실행된다.

 

굳이 이런 상황을 원하는게 아니기에 이를 해결하기 위해 찾아본 결과,

requestAnimationFrame API를 이용하면 해결이 가능하다.

 

자세한 내용과 장점 등은 아래의 블로그 주인분께서 정말 자세히 설명.

https://inpa.tistory.com/entry/%F0%9F%8C%90-requestAnimationFrame-%EA%B0%80%EC%9D%B4%EB%93%9C

 

🌐 웹 애니메이션 최적화 requestAnimationFrame 가이드

자바스크립트 웹 애니메이션 웹페이지의 애니메이션을 구현할때 CSS의 animatoin , transition , transform 속성을 통해 구현할 수도 있지만, 보다 사용자와의 복잡한 상호작용을 구현하게 하기 위해 Javasc

inpa.tistory.com

 

 

구체적인 구현 코드

 

Javascript

const slideContainer = document.querySelector(".slide-content");
const containerLength = slideContainer.children.length;
const slideItemWidth = slideContainer.children[0].offsetWidth;
let slideCount = 0;

function slideBanner() {
  const clonedChildren = slideContainer.children;
  slideContainer.style.transition = "1s ease-out";
  slideContainer.style.left = -slideItemWidth * (slideCount) + "px";
  slideCount++;
  if (slideCount % containerLength == 0) {
    for (let i = 0; i < containerLength; i++) {
      slideContainer.append(clonedChildren[i].cloneNode(true))
    }
  }
}

// requestAnimationFrame 관련은 아래부터

const interval = 1000;
let lastTime = 0;

function animate(timestamp, isClicked = false) {
  if (isClicked) {
    lastTime = timestamp;
  }

  elapsed = timestamp - lastTime;

  if (elapsed >= interval) {
    slideBanner();
    lastTime = timestamp;
  }

  raf = requestAnimationFrame(animate);
}

let raf = requestAnimationFrame(animate);

slideContainer.addEventListener("click", function () {
  slideBanner();
  raf = requestAnimationFrame(timestamp => animate(timestamp, true));
});

 

* 주의 사항

- clearInterval()과는 약간 다르게 동작

 

기본적으로 requestAnimationFrame을 쓰는 방법은,

animation을 적용한 함수 funtion animate() 가 있다고 하면

let raf = requestAnimationFrame(animate); 와 같이 실행하고

일시적으로 멈출때 아래와 같이 사용한다.

cancelAnimationFrame(raf);

 

clearInterval()과 같은 방식으로 작동할 것이라 생각하고 원래는 아래와 같이 작성했었다.

slideContainer.addEventListener("click", function () {
  cancelAnimationFrame(raf);
  slideBanner();
  raf = requestAnimationFrame(animate);
});

그러면 클릭했을 때 raf가 초기화 되었다가

다시 raf=requestAnimationFrame(animate)를 호출한 부분부터 작동할 것이라 생각했다.

그러나 clearInterval()과는 약간 다른 방식으로 작동한다.

 

requestFrameAnimation은 timestamp를 인자로 기본으로 넘겨주는데,

cancelAnimationFrame(raf) 이후에

다시 raf = requestAnimationFrame(animate);를 실행시키는 상황에서

animate function 안에서 console.log(timestamp)를 찍어보면,

timestamp가 지워지지 않고 계속 누적해서 쌓이고 있음을 확인할 수 있다.

 

즉, cancelAnimationFrame 기능으로 일시적인 멈춤을 주는 것이지,

초기화 하는 것처럼 기능하지 않는 것이다.

 

이 때문에, animate 안에 click의 상황인지 아닌지를 이용할 수 있게 isClicked 인자를 넘겨서 판단하고,

slideContainer의 addEventListener 안에서 raf에 requestAnimationFrame을 재지정할 때,

raf = requestAnimationFrame(timestamp => animate(timestamp, isClicked=true));

위와 같이 timestamp와 함께 isClicked=true를 넘겨주는 방식을 이용했다.

elapsed가 지정해준 interVal 이상이 될 때 slideBanner()가 작동하므로

isClicked=true인 경우에 elapsed = 0 이 될 수 있도록 lastTime = timeStamp로 해준다.

 

728x90
반응형