Substr() с отрицательным значением, не работающим в IE

EDIT: я изменил название, потому что проблема не имела никакого отношения к IE image.load() firing - мой substr() не работал (см. принятый ответ).


Там много сообщений о том, что вы определяете свой обработчик onload перед назначением img.src, чтобы гарантировать, что обработчик onload находится на месте, если сначала загружается изображение из кеша.

Это не кажется проблемой в моем коде, так как это именно то, что я сделал.

Обратите внимание, что этот script работает во всех других браузерах, но IE 8 и ниже не запускают встроенную функцию onload.

var i = lastSlideIndex || 1;

while(imagesQueued < MAX_IMAGES){
    var preloadImage = new Image();
    preloadImage.arrayIndex = i;
    preloadImage.onload = function(eventObj){
        debug('Image ' + this.src + ' loaded.');
        slideshowImages[this.arrayIndex] = this;
        if (this.arrayIndex > lastImageIndex) lastImageIndex = this.arrayIndex;
        triggerSlideshow(this.arrayIndex);
    }

    // add leading zeros
    var leadingZeros = "0000000".substr(-(String(MAX_IMAGES).length));
    imageNumber = leadingZeros.substr(String(i).length) + i;

    debug('preloading Image #' + imageNumber);
    preloadImage.src = fullImagePrefix + imageNumber + "." + IMAGES_TLA;

    if (++i > MAX_IMAGES) i = 1;
    imagesQueued++;
}

Любые другие предложения будут глубоко оценены!

Ответ 1

Обновление: Как отмечают комментаторы (и пока не могу доказать их иначе), я удалил первое предложение.

Еще несколько вещей, чтобы отметить:

onload Событие не срабатывает, если изображение загружается из кеша. Попробуйте очистить кеш и повторить попытку.

Другая проблема заключается в том, что IE не любит отрицание в substr. Вместо этого используйте slice:

"0000000".slice(-(String(MAX_IMAGES).length));

Ответ 2

Теперь, когда этот вопрос имеет название substr() в IE 8, здесь быстро исправить проблему с отрицательным индексом. Вставьте следующий код из Mozilla Developer Network:

// only run when the substr() function is broken
if ('ab'.substr(-1) != 'b') {
  /**
   *  Get the substring of a string
   *  @param  {integer}  start   where to start the substring
   *  @param  {integer}  length  how many characters to return
   *  @return {string}
   */
  String.prototype.substr = function(substr) {
    return function(start, length) {
      // call the original method
      return substr.call(this,
        // did we get a negative start, calculate how much it is from the beginning of the string
        // adjust the start parameter for negative value
        start < 0 ? this.length + start : start,
        length);
    }
  }(String.prototype.substr);
};

Этот код обнаруживает сломанную реализацию substr и заменяет его на совместимый.

Ответ 3

Два способа борьбы с этим:

  • Добавьте к URL-адресу изображения параметр nonce.

    var nonce = new Date().getTime();
    
    // ...
    
    preloadImage.src = fullImagePrefix + imageNumber + "." + IMAGES_TLA + ('?_=' + nonce++);
    
  • Задайте свойство "src" в другом цикле событий.

    setTimeout(function(img, src) {
      img.src = src;
    }(preloadImage, fullImagePrefix + imageNumber + "." + IMAGES_TLA), 1);
    

Используя параметр nonce каждый раз, когда вы извлекаете изображение, вы обходите кеш. Теперь это, вероятно, не такая замечательная идея, поэтому второй вариант касается проблемы, убедившись, что свойство "src" задано в отдельном цикле событий. Тогда "load" будет срабатывать.

Здесь показан пример. Код использует nonces на некоторых изображениях, но устанавливает "src" для всех из них в обработчике тайм-аута. Как вы можете видеть, все они загружаются (краснеют).

Я не знаю, почему IE не запускает обработчик "load", когда изображение находится в кеше, но это происходит, когда "src" устанавливается в другом цикле событий, из которого находится объект изображения (в противном случае) инициализированы.

edit — Здесь та же самая скрипка, но изменена, чтобы пропустить таймаут. В IE8 вы должны заметить, что четные изображения часто не получают вызов обработчикам нагрузки.