jQuery检查外部图像宽度

时间:2013-07-14 16:06:15

标签: javascript jquery jquery-mobile external

我在一个小的RSS阅读器上,我想在每篇文章中加载第一张图片,将其设置为主图像。

function getNewsImage(content, request){
var $container = $('<div/>').html(content);

var result = {
     links:[],
     images:[]
}; 

$container.find('a[href],img').each(function() {
    if(this.tagName.toUpperCase() == 'A') {
        result.links.push([this.tagName,this.innerHTML,this.href]);
    } else {
        result.images.push([this.tagName,this.src,this.alt]);
    }
});

var image;

if(request=='link'){
  image = result.links[0][1];
}else{
  if(typeof result.images[0] !== 'undefined'){
    var img = document.createElement('img')
    img.src = result.images[0][1]
    img.onload = function() {
        if(this.width > 20){
            image = result.images[0][1];
            return false;
        }else{
            image = 'images/noImage.png';
            return false;
        }
    }
  }else{
    image = 'images/noImage.png';
  }

      return image;
    }
}

不幸的是它没有返回任何东西。问题是函数img.onload = function(){}不会改变变量图像的值......

有人能告诉我我做错了吗?

1 个答案:

答案 0 :(得分:1)

有几个问题:

  1. 你有竞争条件。您需要在设置onload之前挂钩src 。否则,当您挂钩onload时,该事件可能已被触发。只需交换这两个陈述。 (潜伏者:如果您认为没有竞争条件,请参阅下面的“关于#1的更多内容”。)

  2. 您正在image处理程序中设置局部变量onload。并且您从image函数返回getNewsImage。但是在onload函数返回之后,您的getNewsImage处理程序将被称为,因此在您等待的情况下,它返回的值将为undefined图片。您必须修改getNewsImage以接受它在拥有图片时调用的回调,无法使用return返回它。

  3. ...以及附带问题:如果您最终使用的是链接而不是图片,则可以将image设置为链接的HTML,但不会返回imagereturn image;语句 else子句中仅处理图像。 (请参阅我对有关一致,明确的代码缩进的问题的评论。)


      

    ......我正在努力应对回调..你能否给我一个如何解决这个问题的提示?

    目前,您调用getNewsImage的代码大概如下:

    var image = getNewsImage(someContent, someRequest);
    if (image.src) {
        doSomethingWithTheImage(image);
    }
    else {
        doSomethingWithTheLinkText(image);
    }
    // ...and so on...
    

    你要改变它,以便你像这样使用它:

    getNewsImage(someContent, someRequest, function(image) {
        if (image.src) {
            doSomethingWithTheImage(image);
        }
        else {
            doSomethingWithTheLinkText(image);
        }
        // ...and so on...
    });
    

    然后getNewsImage的签名变为如下所示:

    function getNewsImage(content, request, callback){
    // The new bit -----------------------^^^^^^^^^^
    

    return image;中你永远不会getNewsImage。相反,您将其更改为调用传入的回调并为该回调提供图像:

    callback(image);
    

    ...并确保您始终以异步方式

    E.g:

    function getNewsImage(content, request, callback) {
                          // Change -----^^^^^^^^^^^
      var $container = $('<div/>').html(content);
    
      var result = {
        links: [],
        images: []
      };
    
      var async = true;                               // <== Change
    
      $container.find('a[href],img').each(function () {
        if (this.tagName.toUpperCase() == 'A') {
          result.links.push([this.tagName, this.innerHTML, this.href]);
        }
        else {
          result.images.push([this.tagName, this.src, this.alt]);
        }
      });
    
      if (request == 'link') {
        done(result.links[0][1]);                     // <== Change
      }
      else {
        if (typeof result.images[0] !== 'undefined') {
          var img = document.createElement('img')
          img.onload = function () {
            async = false;                            // <== Change
            if (this.width > 20) {
              done(result.images[0][1]);              // <== Change
            }
            else {
              done('images/noImage.png');             // <== Change
            }
          }
          img.src = result.images[0][1];              // <== Change (moved under `onload`)
        }
        else {
          done('images/noImage.png');                 // <== Change
        }
      }
    
      // New (note this is *within* getNewsImage)
      function done(image) {
        if (async) {
          setTimeout(function() {
            callback(image);
          }, 0);
        }
        else {
          callback(image);
        }
      }
    }
    

    合同是这样的:getNewsImage将与结果异步调用回调。注意,在上面,即使我们同步得到结果,我们仍然安排异步回调;合同是一致的很重要,因为当涉及onload时回调将是异步的,我们确保总是异步(如果需要,使用setTimeout(..., 0))。


    更多关于#1:

    是的,对于那些想知道,竞争条件确实存在,即使浏览器上的JavaScript是单线程的(除非使用网络工作者)。浏览器实现完全有权查看img src get set,查看图像是否在缓存中,并在其内部事件中对该图像上的所有load处理程序进行回调队列(因为没有,所以没有排队)。在当前运行的JavaScript返回到浏览器之前,不允许触发那些回调,但允许对它们进行排队,这就是我们参加比赛的原因。