Как оптимизировать код js?
Есть функция анимации на js. Внутри интервал вызывающий функцию пикселизации изображения. Она занимает много времени и стопорит остальной код для прокрутки страницы. Как правильно переписать код?
function animatePixel(pixelatedImage, index) { let start = Date.now(); let timer = setInterval(() => { let timePassed = Date.now() - start; if (timePassed >= 1500) { clearInterval(timer); resolve(1) } isVisible[index] = false; pixelateImage(originalImage[index], Math.floor((1500 - timePassed) / 100), pixelatedImage); }, 100) } function pixelateImage(originalImage, pixelationFactor, pixelatedImage) { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const originalWidth = originalImage.width; const originalHeight = originalImage.height; const canvasWidth = originalWidth; const canvasHeight = originalHeight; canvas.width = canvasWidth; canvas.height = canvasHeight; context.drawImage(originalImage, 0, 0, originalWidth, originalHeight); const originalImageData = context.getImageData( 0, 0, originalWidth, originalHeight ).data; if (pixelationFactor !== 0) { for (let y = 0; y < originalHeight; y += pixelationFactor) { for (let x = 0; x < originalWidth; x += pixelationFactor) { // extracting the position of the sample pixel const pixelIndexPosition = (x + y * originalWidth) * 4; // drawing a square replacing the current pixels context.fillStyle = `rgba( ${originalImageData[pixelIndexPosition]}, ${originalImageData[pixelIndexPosition + 1]}, ${originalImageData[pixelIndexPosition + 2]}, ${originalImageData[pixelIndexPosition + 3]} )`; context.fillRect(x, y, pixelationFactor, pixelationFactor); } } } pixelatedImage.src = canvas.toDataURL(); } |
function animatePixel(pixelatedImage, index) { let start = Date.now(); let timer = setInterval(() => { let timePassed = Date.now() - start; if (timePassed >= 1500) { clearInterval(timer); resolve(1) } isVisible[index] = false; pixelateImage(originalImage[index], Math.floor((1500 - timePassed) / 100), pixelatedImage); }, 100) } function pixelateImage(originalImage, pixelationFactor, pixelatedImage) { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const originalWidth = originalImage.width; const originalHeight = originalImage.height; const canvasWidth = originalWidth; const canvasHeight = originalHeight; canvas.width = canvasWidth; canvas.height = canvasHeight; context.drawImage(originalImage, 0, 0, originalWidth, originalHeight); const originalImageData = context.getImageData( 0, 0, originalWidth, originalHeight ).data; if (pixelationFactor !== 0) { for (let y = 0; y < originalHeight; y += pixelationFactor) { for (let x = 0; x < originalWidth; x += pixelationFactor) { // extracting the position of the sample pixel const pixelIndexPosition = (x + y * originalWidth) * 4; // drawing a square replacing the current pixels context.fillStyle = `rgba( ${originalImageData[pixelIndexPosition]}, ${originalImageData[pixelIndexPosition + 1]}, ${originalImageData[pixelIndexPosition + 2]}, ${originalImageData[pixelIndexPosition + 3]} )`; context.fillRect(x, y, pixelationFactor, pixelationFactor); } } } pixelatedImage.src = canvas.toDataURL(); }
Дополнительно:
в отдельный поток вынеси через воркер или раздроби originalHeight на части, и через промисы дорисовывай холст
https://www.youtube.com/watch?v=1c4UAd7SNkk
https://developer.mozilla.org/ru/docs/Web/API/Web_...
Ответы:
У тебя дохрена всего лишнего. Как минимум, pixelatedImage.src = canvas.toDataURL(); в каждой итерации - это прямо вишенка на торте.
показывай анимацию на канве, а не в элементе img
Однократно:
1) создать канву нужных размеров, кинуть на неё картинку
2) забрать originalImageData = context.getImageData(...)
3) создать новый targerImageData = context.createImageData(width, height)
На каждой итерации (на каждом срабатывании таймера):
1) Обойдя пиксели originalImageData, заполнить соответствующие квадраты в targerImageData
2) Вызвать context.putImageData(targerImageData, 0, 0)
Если у тебя большая картинка и это всё равно будет подтормажвиать, то стоит попробовать вынести работу с originalImageData и targerImageData в отдельный поток. При этом targerImageData нужно правильно перекидывать между потоками.
Как вариант, можно попробовать раскурить webgl, тут подсказать не могу, не пробовал.
Опишите проблему, и специалист поможет с настройкой, исправлением ошибки или доработкой сайта. Подберём понятный план работ без лишней переписки.
Пока нет других ответов. Будьте первым, кто поможет автору.
Ответить на вопрос
Для оптимизации кода JavaScript можно использовать несколько методов, которые помогут улучшить производительность и эффективность вашего кода. Вот несколько советов:
1. Уменьшение количества запросов к серверу: объединение и минимизация файлов JavaScript поможет уменьшить время загрузки страницы. Можно использовать сборщики (например, Webpack) для объединения и минимизации файлов.
2. Использование кэширования: кэширование позволяет сохранять ресурсы на стороне клиента и уменьшить время загрузки страницы. Можно использовать HTTP-заголовки для управления кэшированием.
3. Оптимизация циклов: избегайте вложенных циклов и используйте более эффективные методы обхода массивов, такие как методы map(), filter() и reduce().
4. Избегайте лишних запросов к DOM: минимизируйте обращения к DOM, так как это является одним из самых медленных операций в JavaScript. Лучше сохранять ссылки на элементы DOM в переменных и обращаться к ним через переменные.
5. Используйте события делегирования: вместо назначения обработчиков событий каждому элементу отдельно, используйте делегирование событий для уменьшения количества обработчиков событий.
Пример оптимизированного кода на JavaScript:
// Уменьшение количества запросов к серверу import { getData } from './api'; const fetchData = async () => { const data = await getData(); // Дальнейшие действия с полученными данными }; // Оптимизация циклов const numbers = [1, 2, 3, 4, 5]; const sum = numbers.reduce((acc, curr) => acc + curr, 0); // Избегание лишних запросов к DOM const button = document.getElementById('myButton'); button.addEventListener('click', () => { // Действия по клику на кнопку }); // Использование событий делегирования const parent = document.getElementById('parentElement'); parent.addEventListener('click', (event) => { if (event.target.classList.contains('childElement')) { // Действия по клику на дочерний элемент } });
Следуя этим советам, вы сможете значительно улучшить производительность вашего кода JavaScript.