jQuery检查外部图像宽度

jQuery check external image width

本文关键字:图像 外部 检查 jQuery      更新时间:2023-09-26

我正在使用一个小型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(){}不会更改变量image的值。。。

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

几个问题:

  1. 你有比赛条件。您需要先挂接onload,然后设置src。否则,当您挂接onload时,事件可能已经被触发。把这两个语句互换一下(潜伏者:如果你认为没有比赛条件,请参阅下面的"关于#1的更多信息"。)

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

还有一个附带问题:如果最终使用的是链接而不是图像,则将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 -----------------------^^^^^^^^^^

getNewsImage中,您从未使用过return image;。相反,您将其更改为调用传入的回调,并为该回调提供图像:

callback(image);

并且确保始终异步执行

例如:

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的设置,查看图像是否在缓存中,并在其内部事件队列中为该图像上的所有load处理程序排队回调(因为没有,所以没有人排队)。在当前运行的JavaScript返回浏览器之前,不允许触发这些回调,但允许对它们进行排队,这就是我们进行竞争的原因。