When does your web page lag behind? Does the input field take too long to respond? You click a button, and it executes three actions?
You suspect it's a performance issue, but maybe it's just the way JavaScript handles events.
Frontend performance optimization isn't just about "minimizing the package"; it's also about ensuring smooth execution flow.
This article focuses on JS execution performance, exploring three angles: throttling, debouncing, and lazy execution. We'll discuss their principles, use cases, and best practices.
**One: JS execution performance issues: Are they caused by events?
JavaScript runs on a single thread, meaning:
- It can only perform one action at a time.
- If JS execution is slow, it blocks rendering and response.
Common lag scenarios:
| **Scenario | **Symptom |
|---|---|
| Scroll binding with onScroll, triggering once per pixel | Page lag significantly |
| Input field binding with onInput to perform a search | Every keystroke sends a request |
| Layout re-rendering on page resize | Browser resizing causes unbearable lag |
We need an approach—don't rush to act immediately.
**Two: Throttling vs. Debouncing: What's the difference?
Throttling:
Definition: Execute the function once every set time
Use case: Scenarios where you want to "time out" before executing an action, such as scrolling, window resize, or mouse movement.
JavaScript implementation:
function throttle(fn, delay) {
let timer = null;
return function (...args) {
if (!timer) {
timer = setTimeout(() => {
fn.apply(this, args);
timer = null;
}, delay);
}
};
}
Usage example:
window.addEventListener('scroll', throttle(() => handleScroll(), 100));
Debouncing:
Definition: Execute the function only after the event has stopped for a set period
Use case: Scenarios where you want to execute the function after the user has completed an action, such as search input, form validation, or button clicks.
JavaScript implementation:
function debounce(fn, delay) {
let timer = null;
return function (...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
Usage example:
input.addEventListener('input', debounce(() => handleInput(), 300));
Key Tip: Remember this rule of thumb:
- Rolling or sliding actions (e.g., scroll, input) → Use throttling
- Clicks or key presses → Use debouncing
- If unsure, try debouncing and measure the user experience
Three: Lazy Execution: Do things when needed, not all at once
"Lazy execution" is a virtue in performance optimization.
1. Lazy DOM rendering: Load content only when needed
Avoid initializing all tab content immediately. Load content after the user triggers it:
function showTab(index) {
if (!document.querySelector(`#tab${index}`)) {
renderTab(index);
}
}
2. Lazy loading of modules (code-level laziness)
const loadEditor = () => import('./RichEditor.vue');
Pair this with dynamic routing and conditional rendering to achieve efficient performance control.
Four: Modern Recommendations: Using lodash and requestIdleCallback
Lodash-based solutions:
import { debounce, throttle } from 'lodash-es';
element.addEventListener('scroll', throttle(() => doSomething(), 100));
- Pros: Performant, concise, and offers cancelable functionality
- Cons: Requires proper initialization
requestIdleCallback: Let the browser say "I'm done; come back later"
requestIdleCallback(() => {
// Perform tasks like statistics reporting or background data loading
});
ideal for scenarios where you want to execute non-critical tasks without blocking the UI.
Note on Compatibility:
Ensure browser compatibility when using the requestIdleCallback function, as older browsers may require adjustments.
Five: Recommendations for Monitoring JS Execution Performance
Use Chrome DevTools → Performance → Flame Chart:
- Analyze function execution time
- Check for blocked主线程
- Identify high-frequency code and layout reordering
Summary: Faster to write, but execution efficiency counts
JS performance isn't just about how fast a function runs in a single execution; it's about how smoothly it runs over time.
Key Takeaways:
- Throttling is for periodic tasks (e.g., scrolling, resize, mouse movement)
- Debouncing is for user-initiated actions (e.g., input, click)
- Lazy execution is for tasks that don't need immediate attention
- Optimizing execution efficiency means reducing unnecessary calculations and improving workflow
Your page not only opens quickly but also responds swiftly.