大数量图片Lazy Load适配咨询:20000张场景及无实图测试方法
Great question! Your current lazy loading code works well for 700 images, but scaling to 20,000 will definitely put it to the test. The good news is you don't need real 100KB images to simulate this scenario—here's how to test effectively, plus some performance tweaks to handle that scale.
How to Test Without Real Images
1. Use Minimal Placeholder Images
Instead of real images, use tiny, inline base64-encoded placeholder images (they won't require any network requests). For example, a 1x1 blank GIF:
// Generate 20,000 test image elements const imageContainer = document.getElementById('your-image-container'); for (let i = 0; i < 20000; i++) { const img = document.createElement('img'); img.className = 'imgli'; // Inline 1x1 blank GIF (no external requests) img.setAttribute('data-src', 'data:image/gif;base64,R0lGODlhAQABAAAAACwAAAAAAQABAAA='); // Simulate real image dimensions (randomize to mimic real layouts) img.style.width = `${Math.floor(Math.random() * 400) + 200}px`; img.style.height = `${Math.floor(Math.random() * 300) + 200}px`; imageContainer.appendChild(img); }
This creates 20,000 image elements with realistic sizes, but the actual "image" data is just a tiny string—no bandwidth or storage needed.
2. Monitor Performance with Browser DevTools
Use your browser's Developer Tools to track how your code handles the load:
- Performance Tab: Record a scrolling session to check for main thread blocking. If your scroll handler takes too long to run (due to looping through 20k elements), you'll see long task bars here.
- Memory Tab: Watch memory usage to ensure there's no leak (e.g., unused event listeners or references piling up).
- Network Tab: Verify no real image requests are being made—all loaded "images" should be the tiny base64 data.
Performance Tweaks for 20,000 Images
Your current code will likely struggle with 20k images because the scroll event fires constantly, and looping through every element on each scroll is inefficient. Here's how to fix that:
1. Add Debouncing to the Scroll Handler
Debouncing ensures your code only runs after scrolling stops (or pauses), reducing the number of times you loop through 20k elements:
function debounce(func, delay = 100) { let timeoutId; return (...args) => { clearTimeout(timeoutId); timeoutId = setTimeout(() => func.apply(this, args), delay); }; } // Wrap your scroll handler with debounce $(window).on('scroll', debounce(function() { // Only target images that haven't been loaded yet (have data-src) $('.imgli[data-src]').each(function() { if ($(this).isInViewport()) { $(this).attr("src", $(this).attr("data-src")).removeAttr('data-src'); } }); }));
2. Use the Intersection Observer API (Recommended)
For large numbers of elements, the native Intersection Observer API is far more performant than manual scroll/viewport checks. It runs asynchronously (doesn't block the main thread) and only triggers when elements enter the viewport:
// Set up the observer const imageObserver = new IntersectionObserver((entries) => { entries.forEach(entry => { if (entry.isIntersecting) { const img = entry.target; // Load the image img.src = img.dataset.src; img.removeAttribute('data-src'); // Stop observing once loaded imageObserver.unobserve(img); } }); }); // Observe all unloaded images document.querySelectorAll('.imgli[data-src]').forEach(img => { imageObserver.observe(img); });
This API is supported in all modern browsers and will drastically reduce main thread load compared to your current approach.
3. Avoid Repeated DOM Queries
Instead of querying $('.imgli[data-src]') on every scroll, cache the list once (and update it as images load):
// Cache the initial list of unloaded images let unloadedImages = $('.imgli[data-src]'); $(window).on('scroll', debounce(function() { unloadedImages.each(function() { if ($(this).isInViewport()) { $(this).attr("src", $(this).attr("data-src")).removeAttr('data-src'); } }); // Update the cache to exclude loaded images unloadedImages = $('.imgli[data-src]'); }));
内容的提问来源于stack exchange,提问作者user7461846

