几个问题:
你有一个竞争条件。设置onload
前需要先钩住src
。否则,当您连接时onload
,该事件可能已经被触发。只需交换两个语句。(潜伏者:如果您认为没有竞争条件,请参阅下面的“更多关于 #1”。)
您正在处理程序中设置一个局部变量image
, onload
。你正在image
从你的getNewsImage
函数中返回。但是您的onload
处理程序将在您的getNewsImage
函数返回后被调用,因此它返回的值将是undefined
您正在等待图像的情况。您必须修改getNewsImage
以接受它在拥有图像时调用的回调,它不能使用return
.
...还有一个附带问题:如果您最终使用链接而不是图像,您将设置image
为链接的 HTML,但您永远不会返回image
. 该return 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);
...并且您确保始终异步执行此操作。
例如:
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 返回给浏览器之前,不允许触发这些回调,但允许将它们排队,这就是我们进行比赛的原因。