Чтобы нарисовать историю:
У меня есть некоторый визуальный контент, который разделен на наборы изображений (плиток).
Я использую простой цикл, который вызывается requestAnimationFrame
чтобы отобразить эти плитки на холсте.
На самом деле я использую PixiJS для этого материала;хотя, возможно, это деталь реализации, которая не совсем относится к этому вопросу.
Потому что может быть много плиток, и потому что я хотел бы, чтобы пользователь мог "несколько немедленно" прокрутить эти наборы плиток, которые я "m предварительно загружает только определенный набор плиток, затем, когда пользователь продолжает навигацию по набору плиток, загружается другой поток плиток, пока не останется больше плиток для загрузки.
Когда визуальный контент полностью загружен, requestAnimationFrame
looop работает хорошо, без каких-либо прерываний.
Но во время отложенной загрузки время от времени возникает некоторая прерывистость.
Я пытался использовать setInterval
для отделения отложенной загрузки (иуправление отходами или сборка мусора тоже) из цикла requestAnimationFrame
.
Но позже я понял, что это связано с тем, что JavaScript имеет только один поток и, следовательно, загрузка изображений блокирует остальную часть кода.Так что setInterval
не помогает;и не будет второго requestAnimatonFrame
вызова для отложенной загрузки.
Затем я читаю о Web Workers, который настраивает возможность одновременного выполнения вещей.Но когда я читаю все данные в потоке Web Worker, они копируются, а не передаются по ссылке.Так что это заняло бы вдвое больше памяти.
И еще я сомневаюсь, что веб-работник будет подходящей функцией для одновременной загрузки плиток, потому что страницы Mozilla Developer Network в основном назначают его в качестве помощи для параллельного (тяжелого)решение для обработки чисел.
Существует определенный тип Web Worker;Сервисный работник, который находится между запросами веб-страницы и веб-сервером.Поможет ли мне сервисный работник при загрузке изображений во время выполнения цикла рисования?
Если нет, знает ли кто-нибудь об альтернативном способе все еще отложенной загрузки, но также анимирует уже загруженный набор изображений?Есть что-то очевидное, что я упустил из виду?
Редактировать 3: Пожалуйста, посмотрите внимательно;заикание происходит во время загрузки изображений;иногда больше, чем в другие времена;но это все еще там;так как я был проинструктирован согласно разделу комментариев, чтобы удалить мою симуляцию, это намного менее очевидно;но заикание все еще там.Проще увидеть, расширяется ли фрагмент кода, а затем после открытия консоли разработчика, перейдя на вкладку «Сеть» и отметив «Отключить кэш», нажмите кнопку «Выполнить».
Редактировать 2: Игнорироватьedit 1. Потому что симуляция была заменена на загрузку реальных изображений.Заикание заметно при первой загрузке изображений или при отключении кэша браузера.
Редактировать 1: Как и требовалось, пример.Ленивое блокирование нагрузки моделируется зацикливанием до выполнения определенной случайной задержки.Предполагается, что цвета представляют мозаичные изображения, но на самом деле они нарисованы на холсте случайным цветом.
var tileImageURLs = [
"https://async.blogjoch.nl/s/W9BcY7RgfNAES38/preview",
"https://async.blogjoch.nl/s/qoHrK9Nz8i7m8Lb/preview",
"https://async.blogjoch.nl/s/ZoAxpcMGF8MPrZH/preview",
"https://async.blogjoch.nl/s/QgTBjbakkSKywpJ/preview",
"https://async.blogjoch.nl/s/G74zo79txm9KHX9/preview",
"https://async.blogjoch.nl/s/cgTy6YswifocsqB/preview",
];
var canvas = document.getElementById('canvas');
var ctx = canvas.getContext('2d');
var y = 0;
var NORMALSPEED = 5;
var currentSpeed = NORMALSPEED;
var TILEWIDTH = 768;
var TILEHEIGHT = 1024;
var TILECOUNT = 6;
var tileImages = [];
var lastTileLoad = -1;
var tileLoadStart = 0;
var PRELOADEDTILESCOUNT = 2;
// For offscreen generation of tiles.
//var tileCanvas = document.createElement('canvas');
//tileCanvas.width = TILEWIDTH;
//tileCanvas.height = TILEHEIGHT;
//var tileCtx = tileCanvas.getContext('2d');
//var tileColors = ['red', 'green', 'blue', 'orange', 'yellow'];
for (var tileIdx = 0; tileIdx < TILECOUNT; tileIdx++) {
tileImages[tileIdx] = document.createElement('img');
tileImages[tileIdx].width = TILEWIDTH;
tileImages[tileIdx].height = TILEHEIGHT;
}
function loadTileImages(tileStart, tileEnd) {
if (tileImages[tileStart]) {
tileImages[tileStart].onload = function() {
// Image loaded; go to next tile if applicable.
if (tileStart + 1 <= tileEnd) {
loadTileImages(++tileStart, tileEnd);
}
}
tileImages[tileStart].src = tileImageURLs[tileStart];
}
}
function loadTiles() {
var tileLoadCount;
if (lastTileLoad < Math.round(y / (canvas.height * 1))) {
/**
* Load checkpoint which lies past previous load checkpoint found;
* so load some stuff.
*/
tileLoadCount = Math.min(tileLoadStart + PRELOADEDTILESCOUNT - 1, TILECOUNT);
loadTileImages(tileLoadStart, tileLoadCount);
tileLoadStart += PRELOADEDTILESCOUNT;
if (tileLoadStart > TILECOUNT - 1) {
/**
* Stop the loading; Infinity is always bigger than a non-infinite number.
*/
console.log('Loading has finished.');
lastTileLoad = Infinity;
} else {
/**
* Store this 'load checkpoint'.
*/
//this.needToDrawFrame = true;
lastTileLoad = Math.round(y / (canvas.height * 1));
}
}
}
function tick() {
var tileImgY;
if (currentSpeed > 0 && (y >= (TILECOUNT * TILEHEIGHT) - canvas.height)) {
currentSpeed = -NORMALSPEED;
} else if (currentSpeed < 0 && (y <= 0)) {
currentSpeed = NORMALSPEED;
}
y += currentSpeed;
loadTiles();
var tileStart = Math.max(Math.floor(y / TILEHEIGHT) - 1, 0);
var tileCount = Math.min(tileStart + Math.ceil(canvas.height / TILEHEIGHT) + 2, TILECOUNT);
//console.log(y, tileStart, tileCount);
ctx.clearRect(0, 0, canvas.width, canvas.height);
for (var tileIndex = tileStart; tileIndex < tileCount; tileIndex++) {
var tileImg = tileImages[tileIndex];
tileImgY = (tileIndex * TILEHEIGHT) - y;
ctx.drawImage(tileImg, 0, tileImgY, TILEWIDTH, TILEHEIGHT);
}
requestAnimationFrame(tick);
}
requestAnimationFrame(tick);
#canvas {
width: 500px;
height: 500px;
border: solid 1px black;
}
<canvas id="canvas" width="768" height="1024"></canvas>