图片加载完成后如何返回

7
首先,我必须承认,在stackoverflow上有数十个类似的问题(例如此处此处和其他无数问题),但这些问题都可以通过回调函数或将代码放入image.onload事件中轻松解决。
image.onload = function () {
    //do other stuff that should be done right after image is loaded
}

但这不是我的情况。这是我的函数签名,负责加载图片:
function patternBuilder (index) {
    var pattern, image, ...
    ...
    image = new Image();
    image.id = "_" + index + "_";
    image.src = "images/_" + index + "_.png";  
    image.onload = function () {
        pattern = ctx.createPattern(image, "repeat");
    }
    return pattern; // !!!! may return undefined if image is not yet loaded
}

所以,我需要返回!我必须这样做,别无选择。我必须遵循这个签名的原因是,这个模式被一些外部库函数使用,看起来像这样:
style: function (feature) {
   var pattern = patternBuilder(feature.get("index"));
   var style = new ol.style.Style({
       fill: new ol.style.Fill({
           color: pattern
       })
   });
   return style;
}

所以,即使我可以改变我的patternBuilder函数的逻辑,我仍然无法更改外部库函数。这个外部函数使用patternBuilder并返回一个样式变量本身。因此,没有回调的空间。

你可以在开始构建模式之前预加载图像吗? - Icepickle
您可能会看到一个参数 index 传递给 patternBuilder。因此,这些图像是动态创建的,我事先不知道所有这些图像是什么。理论上可能有数百个。因此,我需要在需要时加载图像。 - Jacobian
你能把你的代码放在 jsfiddle 或 codepen 上吗?从这里获取你的代码太混乱了。谢谢。 - ristapk
2
所以你的意思是,你需要将异步任务(比如加载图片)变成同步任务(立即返回结果)。那么加载这张图片需要的时间怎么办?基本上你想要的是让整个应用程序/浏览器页面冻结,直到该图片被加载完毕。真的吗?你必须使用异步技术,就像你已经提到的回调函数一样,并且你必须改变你的函数签名来适应这种情况!==> https://dev59.com/RGYq5IYBdhLWcg3wwDRA#14220323 - Thomas
1
正如我之前发布的:你必须将其更改为某些异步实现!如果你说这是一个外部库,而且你无法修复该函数,那么你需要一个不在其核心功能中出现故障的不同库。再次阅读此内容:如何从异步调用中返回响应 - Thomas
显示剩余8条评论
2个回答

1
这里是如何使用Promise的示例:
一个简单的包装器,返回图片Promise:
//takes an url and returns a promise of a (loaded) Image.
function getImage(url){
    return new Promise(function(){
        var image = new Image();
        image.onload = function(){ resolve(image); };
        image.onerror = reject; //TODO: resolve that to sth. better
        image.src = url;
    });
}

和你的patternBuilder

function patternBuilder (index) {
    //returns now a pattern-promise
    return getImage( "images/_" + index + "_.png" ).then(function(image){
        //image.id = "_" + index + "_"; //what exactly is this ID for?
        return ctx.createPattern(image, "repeat");
    });
}

//you may want to add some caching
var patternCache = Object.create(null);
function patternBuilder(index) {
    if(!patternCache[index]){
        patternCache[index] = getImage( "images/_" + index + "_.png" ).then(image => ctx.createPattern(image, "repeat"));
    }
    //still returns pattern-promise, but some may have been resolved a "long time" ago.
    return patternCache[index];
}

你使用模式的函数:
style: function(feature) {
    //returns a style-promise
    return patternBuilder(feature.get("index")).then(function(pattern){
        return new ol.style.Style({
            fill: new ol.style.Fill({
                color: pattern
            })
        })
    })
}

看起来很不错。我会试一下的。 - Jacobian
我尝试过了。我不太擅长JavaScript Promise,所以我不知道出了什么问题以及如何应对,但现在style函数返回一个Promise { <state>: "pending" }对象,而不是样式对象。这导致了其他错误。 - Jacobian
@Jacobian 确实,现在你需要更新使用“style”函数的项目,将其处理为一个Promise,并且还要使用“then”关键字。 - Icepickle

0
你尝试过使用 Promise 吗?你可以控制回调函数,当图片加载完成后返回该函数。

1
这应该是当前状态下的注释 - MJB
抱歉,我以为我还不能评论! - dbmdlr
@dbmdlr 如果您还不能发表评论,您可以通过编辑一些格式不正确的帖子来获得声望和/或回答一些您能够给出好答案的问题,从而获得发表评论的声望。获得发表评论的声望相对容易实现。 - Icepickle
太好了,谢谢你! - dbmdlr

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接