У меня проблема с jQuery.

Я хотел получить реальную ширину / высоту img.
Теперь я использовал эту функцию, чтобы получить это:

var imageSize = function(image) {
    var realImageSize = { };

    $("<img/>") // Make in memory copy of image to avoid css issues
    .attr("src", $(image).attr("src"))
    .load(function() {
        realImageSize.width = this.width;   // Note: $(this).width() will not
        realImageSize.height = this.height; // work for in memory images.

        alert(realImageSize['height']); // Valid height
    });

    alert(realImageSize['height']); // Undefined

    return realImageSize;
}

Поэтому я копирую изображение в память, а затем получаю и устанавливаю реальный размер изображения в методе .load.

Теперь проблема в том, что переменная var realImageSize по этой причине недоступна. Кто-нибудь может сказать мне, почему?

3
NSAddict 31 Янв 2013 в 14:00

3 ответа

Лучший ответ

Это не проблема объема, это нормально, но проблема синхронности: вы читаете значение до того, как будет выполнен обратный вызов загрузки.

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

Обычное решение - не возвращать значение, а предоставить обратный вызов:

var fetchImageSize = function(image, callback) {
    $("<img/>") // Make in memory copy of image to avoid css issues
    .load(function() {
        var realImageSize = { };
        realImageSize.width = this.width;   // Note: $(this).width() will not
        realImageSize.height = this.height; // work for in memory images.
        callback(realImageSize);
    }).attr("src", image.src);
};

fetchImageSize(myImage, function(realImageSize){
    alert(realImageSize['height']); // NOT Undefined
});

Обратите внимание, что вы всегда должны устанавливать src после , когда вы устанавливаете обратный вызов onload. Некоторые браузеры, если у вас есть изображение в кэше, могут не вызывать обратный вызов onload, если вы установите его после установки источника.

6
Denys Séguret 31 Янв 2013 в 10:10

Ваше второе оповещение вызывается до завершения функции загрузки. Обратные вызовы ...

Попробуй это

var imageSize = function(image,callback) {
  var realImageSize = { };

  $("<img/>") // Make in memory copy of image to avoid css issues
  .attr("src", $(image).attr("src"))
  .load(function() {
    realImageSize.width = this.width;   // Note: $(this).width() will not
    realImageSize.height = this.height; // work for in memory images.

    alert(realImageSize['height']); // Valid height
    callback(realImageSize);
  });


}

imageSize(img, function(realImageSize) {
   alert(realImageSize.height);
});
2
bipen 31 Янв 2013 в 10:11

Это распространенная проблема для программистов Javascript, которые приходят из других языков. Javascript использует модель выполнения, называемую Асинхронные вызовы. В двух словах, когда вы регистрируете функцию для события .load(), выполнение функции будет отложено до , когда изображение было загружено , а остальная часть тела функции (т.е. second alert()) выполняется немедленно:

var imageSize = function(image) {
    //runs now
    var realImageSize = { };

    //runs now
    $("<img/>") // Make in memory copy of image to avoid css issues
    .attr("src", $(image).attr("src"))
    .load(function() {
        //this code can run say 5 sec later
        realImageSize.width = this.width;   // Note: $(this).width() will not
        realImageSize.height = this.height; // work for in memory images.

        alert(realImageSize['height']); // Valid height
    });

    //runs now. The realImageSize variable is yet to be created in 5 sec
    alert(realImageSize['height']); // Undefined

    //runs now
    return realImageSize;
}

Распространенным способом решения этой проблемы является передача обратного вызова функции, которая займет много времени.

//** Get an image URL and a callback function that will be called when the image is loaded and the size is detected
function imageSize ( src, callback ) {
    $("<img src="' + src + '"/>").load( function () {
        //here we call the callback which will be called when the image is loaded
        callback({
            width: this.width,
            height: this.height
        });
    });
}

imageSize( 'my/image/path.png', function ( imageSize ) {
    //this callback function will be called when the image is loaded
    alert( 'width: ' + imageSize.width + ', height: ' + imageSize.height );
});
2
AlexStack 31 Янв 2013 в 10:12