Как предотвратить запрос requestAnimationFrame при ленивой загрузке изображений? - PullRequest
0 голосов
/ 23 февраля 2019

Чтобы нарисовать историю:

У меня есть некоторый визуальный контент, который разделен на наборы изображений (плиток).

Я использую простой цикл, который вызывается 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>

1 Ответ

0 голосов
/ 24 февраля 2019

У меня есть ответ на свой вопрос;с моей стороны это была в основном глупость.

Как выяснилось, она выполняла дополнительные вызовы функции тикера (вызывается requestAnimationFrame) во время фазы загрузки (чтобы убедиться, что экран обновляется при поступлении новых изображений тайлов).).

Эти вызовы вызвали всплески дополнительного движения и создали ощущение, что было некоторое заикание (более тяжелое, чем я мог воспроизвести в моем примере, кстати).

Но частьзаикание - микро заикание - ушло после того, как я использовал createImageBitmap в Web Worker для загрузки изображений.

...