Home Web Front-end JS Tutorial Supercharge Your Web Animations: Optimize requestAnimationFrame Like a Pro

Supercharge Your Web Animations: Optimize requestAnimationFrame Like a Pro

Sep 26, 2024 pm 10:23 PM

Supercharge Your Web Animations: Optimize requestAnimationFrame Like a Pro

流暢且高效能的動畫在現代 Web 應用程式中至關重要。然而,管理不當可能會使瀏覽器的主執行緒過載,導致效能不佳和動畫卡頓。 requestAnimationFrame (rAF) 是一種瀏覽器 API,旨在將動畫與顯示器的刷新率同步,從而確保與 setTimeout 等替代方案相比更流暢的運動。但高效使用 rAF 需要仔細規劃,尤其是在處理多個動畫時。

在本文中,我們將探討如何透過集中動畫管理、引入 FPS 控制以及保持瀏覽器主執行緒回應來最佳化 requestAnimationFrame。


了解 FPS 及其重要性

在討論動畫效能時,每秒影格數 (FPS) 至關重要。大多數螢幕以 60 FPS 刷新,這意味著 requestAnimationFrame 每秒被呼叫 60 次。為了保持流暢的動畫,瀏覽器必須在每幀約 16.67 毫秒內完成其工作。

如果在單一影格中執行太多任務,瀏覽器可能會錯過其目標幀時間,從而導致卡頓或丟幀。降低某些動畫的 FPS 有助於減少主執行緒的負載,從而在效能和流暢度之間取得平衡。

具有 FPS 控制功能的集中式動畫管理器可實現更好的效能

為了更有效地管理動畫,我們可以透過共享循環集中處理動畫,而不是在程式碼中分散多個 requestAnimationFrame 呼叫。集中式方法可最大程度地減少冗餘調用,並更輕鬆地添加 FPS 控制。

下面的AnimationManager類別允許我們在控制目標FPS的同時註冊和取消註冊動畫任務。預設情況下,我們的目標是 60 FPS,但這可以根據效能需求進行調整。

class AnimationManager {
  private tasks: Set<FrameRequestCallback> = new Set();
  private fps: number = 60; // Target FPS
  private lastFrameTime: number = performance.now();
  private animationId: number | null = null; // Store the animation frame ID

  private run = (currentTime: number) => {
    const deltaTime = currentTime - this.lastFrameTime;

    // Ensure the tasks only run if enough time has passed to meet the target FPS
    if (deltaTime > 1000 / this.fps) {
      this.tasks.forEach((task) => task(currentTime));
      this.lastFrameTime = currentTime;
    }

    this.animationId = requestAnimationFrame(this.run);
  };

  public registerTask(task: FrameRequestCallback) {
    this.tasks.add(task);
    if (this.tasks.size === 1) {
      this.animationId = requestAnimationFrame(this.run); // Start the loop if this is the first task
    }
  }

  public unregisterTask(task: FrameRequestCallback) {
    this.tasks.delete(task);
    if (this.tasks.size === 0 && this.animationId !== null) {
      cancelAnimationFrame(this.animationId); // Stop the loop if no tasks remain
      this.animationId = null; // Reset the ID
    }
  }
}

export const animationManager = new AnimationManager();
Copy after login

在此設定中,我們計算幀之間的 deltaTime,以確定基於目標 FPS 是否已經過去了足夠的時間進行下一次更新。這使我們能夠限制更新頻率,以確保瀏覽器的主執行緒不會過載。


實際範例:為具有不同屬性的多個元素設定動畫

讓我們建立一個範例,其中我們為三個盒子設定動畫,每個盒子都有不同的動畫:一個縮放,另一個改變顏色,第三個旋轉。

這是 HTML:

<div id="animate-box-1" class="animated-box"></div>
<div id="animate-box-2" class="animated-box"></div>
<div id="animate-box-3" class="animated-box"></div>
Copy after login

這是 CSS:

.animated-box {
  width: 100px;
  height: 100px;
  background-color: #3498db;
  transition: transform 0.1s ease;
}
Copy after login

現在,我們將新增 JavaScript 來為每個具有不同屬性的方塊設定動畫。一個會縮放,另一個會改變顏色,第三個會旋轉。

第 1 步:新增線性內插 (lerp)

線性插值 (lerp) 是動畫中常用的技術,用於在兩個值之間平滑過渡。它有助於創建漸進且平滑的進程,使其成為隨時間推移縮放、移動或更改屬性的理想選擇。此函數採用三個參數:起始值、結束值和標準化時間 (t),該時間決定過渡的距離。

function lerp(start: number, end: number, t: number): number {
  return start + (end - start) * t;
}
Copy after login

第 2 步:縮放動畫

我們先建立一個函數來為第一個框的縮放設定動畫:

function animateScale(
  scaleBox: HTMLDivElement,
  startScale: number,
  endScale: number,
  speed: number
) {
  let scaleT = 0;

  function scale() {
    scaleT += speed;
    if (scaleT > 1) scaleT = 1;

    const currentScale = lerp(startScale, endScale, scaleT);
    scaleBox.style.transform = `scale(${currentScale})`;

    if (scaleT === 1) {
      animationManager.unregisterTask(scale);
    }
  }

  animationManager.registerTask(scale);
}
Copy after login

第 3 步:彩色動畫

接下來,我們為第二個框的顏色變化設定動畫:

function animateColor(
  colorBox: HTMLDivElement,
  startColor: number,
  endColor: number,
  speed: number
) {
  let colorT = 0;

  function color() {
    colorT += speed;
    if (colorT > 1) colorT = 1;

    const currentColor = Math.floor(lerp(startColor, endColor, colorT));
    colorBox.style.backgroundColor = `rgb(${currentColor}, 100, 100)`;

    if (colorT === 1) {
      animationManager.unregisterTask(color);
    }
  }

  animationManager.registerTask(color);
}
Copy after login

第 4 步:旋轉動畫

最後,我們建立旋轉第三個框的函數:

function animateRotation(
  rotateBox: HTMLDivElement,
  startRotation: number,
  endRotation: number,
  speed: number
) {
  let rotationT = 0;

  function rotate() {
    rotationT += speed; // Increment progress
    if (rotationT > 1) rotationT = 1;

    const currentRotation = lerp(startRotation, endRotation, rotationT);
    rotateBox.style.transform = `rotate(${currentRotation}deg)`;

    // Unregister task once the animation completes
    if (rotationT === 1) {
      animationManager.unregisterTask(rotate);
    }
  }

  animationManager.registerTask(rotate);
}
Copy after login

第 5 步:開始動畫

最後,我們可以啟動所有三個盒子的動畫:

// Selecting the elements
const scaleBox = document.querySelector("#animate-box-1") as HTMLDivElement;
const colorBox = document.querySelector("#animate-box-2") as HTMLDivElement;
const rotateBox = document.querySelector("#animate-box-3") as HTMLDivElement;

// Starting the animations
animateScale(scaleBox, 1, 1.5, 0.02); // Scaling animation
animateColor(colorBox, 0, 255, 0.01); // Color change animation
animateRotation(rotateBox, 360, 1, 0.005); // Rotation animation
Copy after login

主線程注意事項

使用 requestAnimationFrame 時,必須記住動畫在瀏覽器的主執行緒上運行。主執行緒超載過多的任務可能會導致瀏覽器錯過動畫幀,從而導致卡頓。這就是為什麼使用集中式動畫管理器和 FPS 控制等工具來最佳化動畫可以幫助保持流暢度,即使有多個動畫也是如此。


結論

在 JavaScript 中有效管理動畫需要的不僅僅是使用 requestAnimationFrame。透過集中動畫並控制 FPS,您可以確保動畫更流暢、效能更高,同時保持主執行緒回應能力。在此範例中,我們展示如何使用單一 AnimationManager 處理多個動畫,示範如何最佳化效能和可用性。雖然為了簡單起見,我們專注於保持一致的 FPS,但這種方法可以擴展到處理各種動畫的不同 FPS 值,儘管這超出了本文的範圍。

Github Repo: https://github.com/JBassx/rAF-optimization
StackBlitz: https://stackblitz.com/~/github.com/JBassx/rAF-optimization

LinkedIn: https://www.linkedin.com/in/josephciullo/

The above is the detailed content of Supercharge Your Web Animations: Optimize requestAnimationFrame Like a Pro. For more information, please follow other related articles on the PHP Chinese website!

Statement of this Website
The content of this article is voluntarily contributed by netizens, and the copyright belongs to the original author. This site does not assume corresponding legal responsibility. If you find any content suspected of plagiarism or infringement, please contact admin@php.cn

Hot AI Tools

Undresser.AI Undress

Undresser.AI Undress

AI-powered app for creating realistic nude photos

AI Clothes Remover

AI Clothes Remover

Online AI tool for removing clothes from photos.

Undress AI Tool

Undress AI Tool

Undress images for free

Clothoff.io

Clothoff.io

AI clothes remover

Video Face Swap

Video Face Swap

Swap faces in any video effortlessly with our completely free AI face swap tool!

Hot Tools

Notepad++7.3.1

Notepad++7.3.1

Easy-to-use and free code editor

SublimeText3 Chinese version

SublimeText3 Chinese version

Chinese version, very easy to use

Zend Studio 13.0.1

Zend Studio 13.0.1

Powerful PHP integrated development environment

Dreamweaver CS6

Dreamweaver CS6

Visual web development tools

SublimeText3 Mac version

SublimeText3 Mac version

God-level code editing software (SublimeText3)

Hot Topics

Java Tutorial
1664
14
PHP Tutorial
1266
29
C# Tutorial
1239
24
Demystifying JavaScript: What It Does and Why It Matters Demystifying JavaScript: What It Does and Why It Matters Apr 09, 2025 am 12:07 AM

JavaScript is the cornerstone of modern web development, and its main functions include event-driven programming, dynamic content generation and asynchronous programming. 1) Event-driven programming allows web pages to change dynamically according to user operations. 2) Dynamic content generation allows page content to be adjusted according to conditions. 3) Asynchronous programming ensures that the user interface is not blocked. JavaScript is widely used in web interaction, single-page application and server-side development, greatly improving the flexibility of user experience and cross-platform development.

The Evolution of JavaScript: Current Trends and Future Prospects The Evolution of JavaScript: Current Trends and Future Prospects Apr 10, 2025 am 09:33 AM

The latest trends in JavaScript include the rise of TypeScript, the popularity of modern frameworks and libraries, and the application of WebAssembly. Future prospects cover more powerful type systems, the development of server-side JavaScript, the expansion of artificial intelligence and machine learning, and the potential of IoT and edge computing.

JavaScript Engines: Comparing Implementations JavaScript Engines: Comparing Implementations Apr 13, 2025 am 12:05 AM

Different JavaScript engines have different effects when parsing and executing JavaScript code, because the implementation principles and optimization strategies of each engine differ. 1. Lexical analysis: convert source code into lexical unit. 2. Grammar analysis: Generate an abstract syntax tree. 3. Optimization and compilation: Generate machine code through the JIT compiler. 4. Execute: Run the machine code. V8 engine optimizes through instant compilation and hidden class, SpiderMonkey uses a type inference system, resulting in different performance performance on the same code.

Python vs. JavaScript: The Learning Curve and Ease of Use Python vs. JavaScript: The Learning Curve and Ease of Use Apr 16, 2025 am 12:12 AM

Python is more suitable for beginners, with a smooth learning curve and concise syntax; JavaScript is suitable for front-end development, with a steep learning curve and flexible syntax. 1. Python syntax is intuitive and suitable for data science and back-end development. 2. JavaScript is flexible and widely used in front-end and server-side programming.

JavaScript: Exploring the Versatility of a Web Language JavaScript: Exploring the Versatility of a Web Language Apr 11, 2025 am 12:01 AM

JavaScript is the core language of modern web development and is widely used for its diversity and flexibility. 1) Front-end development: build dynamic web pages and single-page applications through DOM operations and modern frameworks (such as React, Vue.js, Angular). 2) Server-side development: Node.js uses a non-blocking I/O model to handle high concurrency and real-time applications. 3) Mobile and desktop application development: cross-platform development is realized through ReactNative and Electron to improve development efficiency.

How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) How to Build a Multi-Tenant SaaS Application with Next.js (Frontend Integration) Apr 11, 2025 am 08:22 AM

This article demonstrates frontend integration with a backend secured by Permit, building a functional EdTech SaaS application using Next.js. The frontend fetches user permissions to control UI visibility and ensures API requests adhere to role-base

From C/C   to JavaScript: How It All Works From C/C to JavaScript: How It All Works Apr 14, 2025 am 12:05 AM

The shift from C/C to JavaScript requires adapting to dynamic typing, garbage collection and asynchronous programming. 1) C/C is a statically typed language that requires manual memory management, while JavaScript is dynamically typed and garbage collection is automatically processed. 2) C/C needs to be compiled into machine code, while JavaScript is an interpreted language. 3) JavaScript introduces concepts such as closures, prototype chains and Promise, which enhances flexibility and asynchronous programming capabilities.

Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Building a Multi-Tenant SaaS Application with Next.js (Backend Integration) Apr 11, 2025 am 08:23 AM

I built a functional multi-tenant SaaS application (an EdTech app) with your everyday tech tool and you can do the same. First, what’s a multi-tenant SaaS application? Multi-tenant SaaS applications let you serve multiple customers from a sing

See all articles