How to Run a JavaScript Function on Page Load

Getting code to fire at the right moment can feel like juggling while riding a unicycle. We often focus on writing logic but overlook when it runs. One key moment is page load, and a frequently missed detail is choosing the correct event. How can you pick the right hook to initialize your script without unexpected errors?
By understanding the different load events and wrappers, you’ll ensure your functions run exactly when the DOM and assets are ready. This clarity helps you avoid race conditions, improve performance, and deliver a smoother user experience.
Why Load Timing Matters
When you build a web page, you want your scripts to manipulate elements reliably. If you run code too soon, the DOM might not exist yet. If you wait too long, you lose precious milliseconds and may hurt user experience. By handling page load correctly, you reduce bugs and make your interface feel snappy.
Here’s what can go wrong:
- Trying to access elements that aren’t in the DOM yet
- Overlapping with image or asset downloads, delaying scripts
- Blocking critical rendering paths unnecessarily
A proper load handler ensures:
- Your scripts can safely query and modify DOM elements.
- You don’t stall the loading of other page resources.
- You separate initialization logic from user interactions.
Choosing the Right Event
Two main events help you run code on load: window.onload
and DOMContentLoaded
. Each has its use case:
Event | Fires When | Use Case |
window.onload | All assets (images, stylesheets, etc.) have loaded | When you need every resource to be ready |
DOMContentLoaded | HTML parsed and DOM built | When you only need the DOM structure |
Tip: If you only manipulate HTML elements, prefer
DOMContentLoaded
. It fires earlier and speeds perceived load.
// Wait for full load
window.onload = function() {
console.log('Everything is loaded');
};
// Wait for DOM only
document.addEventListener('DOMContentLoaded', function() {
console.log('DOM is ready');
});
Learn more about the DOM and its events in What is JavaScript DOM?
Using addEventListener
The modern, flexible way to handle load events is with addEventListener
. It lets you attach multiple handlers and keep your code modular. If you assign directly to window.onload
, a second assignment will overwrite the first.
Example:
function initGallery() {
// gallery setup code
}
function initAnalytics() {
// analytics setup code
}
window.addEventListener('load', initGallery);
window.addEventListener('load', initAnalytics);
This approach:
- Keeps handlers separate
- Allows easy removal via
removeEventListener
- Works with any event, not just
load
Note: Use named functions to simplify removing listeners and improve readability.
IIFE and Self-Executing Wrappers
Immediately Invoked Function Expressions (IIFE) can wrap your load logic in a private scope. This pattern avoids global pollution and keeps variables local.
(function() {
window.addEventListener('load', function() {
// your startup code
});
})();
Or you can self-execute only after load:
window.addEventListener('load', (function() {
return function() {
console.log('IIFE running on load');
};
})());
Benefits of IIFE:
- Encapsulates private state
- Prevents variable clashes
- Clarifies intent: this block runs exactly once on load
If you use callbacks extensively, check out What is a JavaScript callback? to solidify your understanding.
Framework Hooks
If you’re working in React, Vue, or Angular, you often don’t use raw load events. Instead, you tap into lifecycle methods:
- React: useEffect(() => { / init / }, []);
- Vue: mounted() { / init / }
- Angular: ngOnInit() { / init / }
These hooks fire when the component mounts, which roughly aligns with page load for single-page apps. They give you:
- Granular control per component
- Automatic cleanup patterns
- Integration with state and props
// React example
import { useEffect } from 'react';
function App() {
useEffect(() => {
console.log('App mounted');
}, []);
return <div>My App</div>;
}
Best Practices and Performance
Even simple load handlers can hurt performance if misused. Keep these tips in mind:
- Bundle initialization: Combine related startup tasks into one handler.
- Defer heavy work: Use
requestIdleCallback
or split tasks if you have heavy computation. - Avoid blocking: Don’t perform large DOM queries or synchronous XHR on load.
- Lazy-load assets: Only load images or data when needed, not all at once.
Remember: Page speed matters. Every millisecond counts toward user satisfaction.
Wrapping your load logic into well-structured functions keeps your code clean and maintainable.
Conclusion
Running JavaScript on page load is a small detail with big impact. The right event—whether DOMContentLoaded
, window.onload
, or a framework hook—ensures your scripts run at the optimal time. Using addEventListener
and IIFE patterns keeps code modular and avoids global side effects. In larger apps, tap into your framework’s lifecycle methods to manage component-level initialization. Finally, follow performance best practices: bundle tasks, defer heavy work, and avoid blocking the main thread.
By mastering these techniques, you’ll ship smoother interfaces, avoid unpredictable bugs, and deliver a better experience for your users.
Run a JavaScript function on page load using window.onload, DOMContentLoaded, or addEventListener('load') to reliably start your code.
Subscribe to my newsletter
Read articles from Mateen Kiani directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
