Пожар события после предварительной загрузки изображений

Это код, который я использую для предварительной загрузки изображений, я не уверен, что он лучший. Мой вопрос в том, как я могу запустить огонь и событие, например, alert(); диалоговое окно после завершения загрузки всех изображений?

var preload = ["a.gif", "b.gif", "c.gif"];
    var images = [];
    for (i = 0; i < preload.length; i++) {
        images[i] = new Image();
        images[i].src = preload[i];
    }

Ответы

Ответ 1

Вы можете использовать новый "$.Deferred", если хотите:

var preload = ["a.gif", "b.gif", "c.gif"];
var promises = [];
for (var i = 0; i < preload.length; i++) {
    (function(url, promise) {
        var img = new Image();
        img.onload = function() {
          promise.resolve();
        };
        img.src = url;
    })(preload[i], promises[i] = $.Deferred());
}
$.when.apply($, promises).done(function() {
  alert("All images ready sir!");
});

Возможно, будет немного рискованно оставлять объекты Image, плавающие вокруг, но если это можно легко устранить, сдвинув замыкание. на самом деле я сам его поменю, потому что это меня забивает: -)

Ответ 2

Поскольку ваши теги включают jQuery, вот что я сделал бы в jQuery, с тяжелым вдохновением этого связанного ответа:

function preloadImages(images, callback) {
    var count = images.length;
    if(count === 0) {
        callback();
    }
    var loaded = 0;
    $(images).each(function() {
        $('<img>').attr('src', this).load(function() {
            loaded++;
            if (loaded === count) {
                callback();
            }
        });
    });
};

// use whatever callback you really want as the argument
preloadImages(["a.gif", "b.gif", "c.gif"], function() {
    alert("DONE");
});

Это зависит от обратного вызова функции загрузки jQuery.

Я бы не использовал связанный ответ просто потому, что мне не нравилось сбрасывать с помощью встроенных прототипов Javascript.

Ответ 3

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

Первое решение - задержать событие onLoad вместо document.ready. Но это событие может быть довольно долго ждать. Поэтому они используют jquery.imagesloaded.js, который может обнаружить, что загружаются все изображения в div; особенно этот очень короткий и красивый код может обрабатывать кешированные изображения, которые иногда не запускают событие загрузки.

Ответ 4

Отъезд: http://engineeredweb.com/blog/09/12/preloading-images-jquery-and-javascript. Он использует jQuery. В комментариях ваша прямая проблема адресуется кем-то, и там было отправлено решение. Я думаю, это будет соответствовать вашим потребностям.

Ответ 5

В качестве альтернативы вы можете использовать технику CSS для предварительной загрузки изображений, как показано здесь:

http://perishablepress.com/press/2008/06/14/a-way-to-preload-images-without-javascript-that-is-so-much-better/

а затем используйте глобальное событие onLoad, которое запускается, когда все загружено

Ответ 6

//Вот метод pre-jquery, но jquery должен быть проще писать.

function loadAlbum(A, cb, err, limit){
    // A is an array of image urls;
    //cb is a callback function (optional);
    //err is an error handler (optional);
    // limit is an (optional) integer time limit in milliseconds

    if(limit) limit= new Date().getTime()+limit;
    var album= [], L= A.length, tem, url;

    while(A.length){
        tem= new Image;
        url= A.shift();
        tem.onload= function(){
            album.push(this.src);
        }
        tem.onerror= function(){
            if(typeof er== 'function') album.push(er(this.src));
            else album.push('');
        }
        tem.src= url;

        // attend to images in cache (may not fire an onload in some browsers):
        if(tem.complete && tem.width> 0){
            album.push(tem.src);
            tem.onload= '';
        }
    }
    // check the length of the loaded array of images at intervals:
    if(typeof cb== 'function'){
        window.tryAlbum= setInterval(function(){
            if(limit && limit-new Date().getTime()<0) L= album.length;
            if(L== album.length){
                clearInterval(tryAlbum);
                tryAlbum= null;
                return cb(album);
            }
        },
        100);
    }
    return album;
}

Ответ 7

Я ищу методы, которые работают для этого в течение всего дня, и наконец нашел решение всех моих проблем: https://github.com/htmlhero/jQuery.preload

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

Ответ 8

jquery предварительная загрузка нескольких изображений последовательно может выполняться с обратным вызовом.

function preload_images(images_arr, f, id){
    id = typeof id !== 'undefined' ? id : 0;
    if (id == images_arr.length)
        return;
    $('<img>').attr('src', images_arr[id]).load(function(){
        console.log(id);
        f(images_arr[id], id);
        preload_images(images_arr, f, id+1);
    });
}

Например:

preload_images(["img1.jpg", "img2.jpg"], function(img_url, i){
    // i is the index of the img in the original array
    // can make some img.src = img_url
});

Ответ 9

Основываясь на ответе Ben Clayton выше.

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

Вот мой пересмотренный ответ. Один из них легко обнаруживает, что многие изображения загружены с успехом, и сколько оказалось в ошибке. this в обратном вызове будет иметь эту информацию

preloadImages(_arrOfImages, function() {
  var response = this;
  var hasError = response.errored.length + response.aborted.length;
  if (hasError > 0) {
    console.log('failed ' + hasError);
  } else {
    console.log('all loaded');
  }
});

// JSFIDDLE: https://jsfiddle.net/bababalcksheep/ds85yfww/2/

var preloadImages = function(preload, callBack) {
  var promises = [];
  var response = {
    'loaded': [],
    'errored': [],
    'aborted': []
  };
  for (var i = 0; i < preload.length; i++) {
    (function(url, promise) {
      var img = new Image();
      img.onload = function() {
        response.loaded.push(this.src);
        promise.resolve();
      };
      // Use the following callback methods to debug
      // in case of an unexpected behavior.
      img.onerror = function() {
        response.errored.push(this.src);
        promise.resolve();
      };
      img.onabort = function() {
        response.aborted.push(this.src);
        promise.resolve();
      };
      //
      img.src = url;
    })(preload[i], promises[i] = $.Deferred());
  }
  $.when.apply($, promises).done(function() {
    callBack.call(response);
  });
};

Ответ 10

Сегодня мне нужно было предварительно загрузить изображения и выполнить код только после загрузки всех изображений, но без jQuery и с помощью Ionic2/Typcript2. Здесь мое решение:

// Pure Javascript Version
function loadImages(arrImagesSrc) {
    return new Promise(function (resolve, reject) {
        var arrImages = [];
        function _loadImage(src, arr) {
            var img = new Image();
            img.onload = function () { arr.push([src, img]); };
            img.onerror = function () { arr.push([src, null]); };

            img.src = src;
        }
        arrImagesSrc.forEach(function (src) {
            _loadImage(src, arrImages);
        });
        var interval_id = setInterval(function () {
            if (arrImages.length == arrImagesSrc.length) {
                clearInterval(interval_id);
                resolve(arrImages);
            }
        }, 100);
    });
}

// Ionic2 version
private loadImages(arrImagesSrc: Array<string>): Promise<Array<any>> {
    return new Promise((resolve, reject) => {
      ...
      function _loadImage(src: string, arr: Array<any>) {
        ...
      }
      ...
 }

Вы можете использовать это. Проблематичный url возвращает "null".

loadImages(['https://cdn2.iconfinder.com/data/icons/nodejs-1/512/nodejs-512.png', 'http://foo_url'])
.then(function(arr) {
   console.log('[???]', arr); 
})