Могу ли я синхронизировать несколько вызовов при загрузке изображений? - PullRequest
6 голосов
/ 30 декабря 2011

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

Image1 = new Image();
Image1.src = 'image1-link.jpg';

Image2 = new Image();
Image2.src = 'image2-link.jpg';

Image1.onload = function() {
    Image2.onload = function() { ... }
}

Недостатком является то, что нужно дождаться полной загрузки Image1, прежде чем получить вторую. Я хочу попробовать что-то вроде этого:

Image1 = new Image();
Image1.src = 'image1-link.jpg';

Image2 = new Image();
Image2.src = 'image2-link.jpg';

(Image1 && Image2).onload = function() { ... }

РЕДАКТИРОВАТЬ: Спасибо вам обоим за помощь Пола Грайма и Циземера. Оба ваших ответа очень хороши. Я думаю, что должен дать лучший ответ Полу Грайму, хотя он использует больше кода, мне нужно только знать src изображений и встроенную функцию загрузки, в то время как в ответе ziesemer мне нужно знать и src, и количество изображений, и должны написать несколько строк загрузки.

В зависимости от ситуации оба имеют свое назначение. Спасибо вам обоим за помощь.

Ответы [ 3 ]

11 голосов
/ 30 декабря 2011

Эта скрипка может помочь. Это простой общий «загрузчик».

http://jsfiddle.net/8baGb/1/

И код:

// loader will 'load' items by calling thingToDo for each item,
// before calling allDone when all the things to do have been done.
function loader(items, thingToDo, allDone) {
    if (!items) {
        // nothing to do.
        return;
    }

    if ("undefined" === items.length) {
        // convert single item to array.
        items = [items];
    }

    var count = items.length;

    // this callback counts down the things to do.
    var thingToDoCompleted = function (items, i) {
        count--;
        if (0 == count) {
            allDone(items);
        }
    };

    for (var i = 0; i < items.length; i++) {
        // 'do' each thing, and await callback.
        thingToDo(items, i, thingToDoCompleted);
    }
}

function loadImage(items, i, onComplete) {
    var onLoad = function (e) {
        e.target.removeEventListener("load", onLoad);

        // this next line can be removed.
        // only here to prove the image was loaded.
        document.body.appendChild(e.target);

        // notify that we're done.
        onComplete(items, i);
    }
    var img = new Image();
    img.addEventListener("load", onLoad, false);
    img.src = items[i];
}

var items = ['http://bits.wikimedia.org/images/wikimedia-button.png',
             'http://bits.wikimedia.org/skins-1.18/common/images/poweredby_mediawiki_88x31.png',
             'http://upload.wikimedia.org/wikipedia/en/thumb/4/4a/Commons-logo.svg/30px-Commons-logo.svg.png',
             'http://upload.wikimedia.org/wikipedia/commons/3/38/Icons_example.png'];

loader(items, loadImage, function () {
    alert("done");
});
10 голосов
/ 30 декабря 2011

Если вы не можете использовать что-то вроде jQuery, создайте вспомогательную функцию, которую вы можете передать onload всех ваших изображений, которые вас интересуют. Каждый раз, когда она вызывается, увеличивайте счетчик или добавляйте * 1002.* имя для набора.Как только счетчик или ваш набор достигнет размера всех ожидаемых вами изображений, вы можете запустить любую работу, которую вы действительно хотели сделать.

Что-то вроде:

var imageCollector = function(expectedCount, completeFn){
  var receivedCount;
  return function(){
    if(++receivedCount == expectedcount){
      completeFn();
    }
  };
}();

var ic = imageCollector(2, function(){alert("Done!");});
Image1.onload = ic;
Image2.onload = ic;
1 голос
/ 21 апреля 2017

Я взял приведенный выше пример Пола Грайма и изменил его, чтобы он был более понятным, но при этом выполнял ОП. Я чувствовал, что другие ответы здесь были либо сложными, либо недостаточно. Надеюсь, этот код будет немного проще подобрать и вставить. Я использовал подчеркивание для каждого цикла, но это легко изменить.

Кроме того, теперь я улучшил решение, чтобы иметь возможность обратного вызова для ошибки img. Если изображение загружено, оно добавляется в массив, в случае неудачи - нет. Я также изменил его, чтобы использовать jquery.

var loadedImages = [],
    imagePaths = [{"src": "myimg.png"}, {"src": "myotherimg.png"}];

loadImages(imagePaths, loadedImages, function(loadedImages) {
    console.log(loadedImages)
});

function loadImages(imagePaths, loadedImages, callback) {
    if (!imagePaths) { return; }

    var count = imagePaths.length;

    _.each(imagePaths, function(data, key, list) {
        var onLoad = function (e) {
            count--;
            if (0 == count) {
                callback(loadedImages);
            }
        }

        $(document.createElement("img"))
            .on('load', function() {  
                loadedImages.push(data);
                onLoad();
            })
            .on('error', function() {  onLoad(); })
            .attr("src", data["src"]);
    });
},
...