Как сбросить p5.js эскиз, если он не загружается

#javascript #p5.js

Вопрос:

здравствуйте, у меня есть эскиз, который в основном извлекается из гигантской базы данных из более чем 8000 изображений, чтобы выбрать изображение. иногда изображение не загружается, и мне не представляется возможным просмотреть все 8000 изображений и найти, какие из них заставляют мой эскиз зависать при «Загрузке…».

я просто хочу, чтобы можно было сбросить эскиз, если выбранное изображение не загружается, и просто выбрать следующее изображение или случайное изображение или изображение-заполнитель в случае, если оно не загружается, вместо того, чтобы просто висеть на экране «Загрузка…».

кажется, это действительно простая вещь, но я не могу найти никакого простого решения. я попытался создать скрипт, чтобы проверить, существует ли div «p5_loading» после периода ожидания, но затем я понял, что, поскольку эскиз не загружается, если он сломан, мой тайм-аут никогда не закончится, чтобы проверить, не сломан ли он.

Спасибо.

Ответ №1:

Плохая новость заключается в том, что preload() и loadImage() в этом отношении есть некоторые серьезные недостатки. Способ preload() работает так, что когда вы его объявите, p5.js обертывает все loadXXX() функции функцией, которая увеличивает счетчик, прежде чем фактически вызывать базовую loadXXX() функцию. loadXXX() Затем каждая функция уменьшает счетчик предварительной загрузки, но только в том случае, если ресурс загружен успешно. В результате, если только кто-то не прибегнет к доступу p5.js внутренние устройства, нет возможности повторить попытку или восстановиться после ошибки во время предварительной загрузки.

Кроме loadImage() того, не имеет хорошей логики обработки ошибок. Проблема в том, что loadImage() сначала выполняется fetch() запрос ресурса, и если это не вызывает ошибки, он создает Image объект и использует его src свойство для фактической загрузки данных изображения. Проблема в том, что он не проверяет код состояния ответа, и Image объект не генерирует подробную информацию об ошибке. Я бы зашел так далеко, что назвал это недостатком в p5.js стоит того, чтобы подать заявку на GitHub. Как следствие, любой надежный загрузчик, который использует loadImage() , должен одинаково относиться ко всем сбоям загрузки (в отличие от интеллектуального решения, которое рассматривало бы ошибки 5xx и тайм-ауты как возможные для повторной попытки, но рассматривало бы ошибки 4xx как не стоящие повторной попытки).

Итак, учитывая плохие новости, что мы могли бы сделать? Сверните наш собственный загрузочный экран и используйте несколько неоптимальную обработку ошибок с loadImage() :

 const availableImages = [1, 2, 3, 4, 5];
const loading = {};
const loaded = [];
const size = 50;
const maxRetries = 3;

let isLoading = true;

function robustLoad(success, failure) {
  // select a random image
  let ix = floor(random(0, availableImages.length));
  // remove that image from the list of available images
  let id = availableImages.splice(ix, 1)[0];
  
  console.log(`attempting to load image id ${id}`);
  function tryLoadImage(retryCount) {
    loading[id] = loadImage(
      `https://robustp5jspreload.kumupaul.repl.co/get-image?id=${id}`,
      () => {
        // success
        loaded.push(loading[id]);
        delete loading[id];
        success();
      },
      err => {
        console.warn(`error loading image ${id}`);
        console.log(err);
        if (retryCount < maxRetries) {
          console.log(`retrying image ${id}`);
          tryLoadImage(retryCount   1);
        } else {
          // throw in the towel on this id
          delete loading[id];
          if (availableImages.length > 0) {
            robustLoad(success, failure);
          } else {
            failure();
          }
        }
      }
    );
  }

  tryLoadImage(0);
}

function setup() {
  createCanvas(windowWidth, windowHeight);

  background(200);
  textSize(48);
  textAlign(LEFT, TOP);
  text('Loading...', 10, 10);

  // attempt to load two random images
  let status = [false, false];
  for (let n = 0; n < 2; n  ) {
    let currentN = n;
    robustLoad(
      () => {
        status[currentN] = true;
        if (status.every(v => v)) {
          // We're done loading.
          isLoading = false;
          drawBg();
          loop();
        }
      },
      () => {
        console.warn(`unable to load image ${currentN}`);
      }
    );
  }
}

function drawBg() {
  let i = 0;
  let j = 0;
  for (let y = 0; y < height; y  = size) {
    for (let x = 0; x < width; x  = size) {
      image(loaded[i   % loaded.length], x, y, size, size);
    }
    i =   j;
  }
}

function draw() {
  if (!isLoading) {
    circle(mouseX, mouseY, 30);
  }
} 
 <script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script> 

Примечание: Этот пример не предназначен для того, чтобы вы просто использовали его как есть. Это всего лишь пример одной из возможных реализаций.

Источник, из которого я загружаю изображение, является доказательством концепции, которую я создал на Replit, которая возвращает 502 в 66% случаев. В результате теоретически в каком-то проценте случаев он полностью выйдет из строя.

Комментарии:

1. Одной из альтернатив было бы преобразовать ваш эскиз в режим экземпляра, и в обработчике ошибок loadImage() вы могли бы вызвать remove() , а затем повторно создать свой эскиз. Недостатком этого подхода является то, что если вы загружаете кучу изображений, вам придется перезапускаться с нуля, вместо того чтобы восстанавливаться, повторяя или пропуская одно плохое изображение.