Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to return after image is loaded [duplicate]

Tags:

javascript

First of all, I must confess, that there are dozens of similar questions here at stackoverflow (this, this and myriads of others), but all of them are nicely solved with the help of a callback function or simply putting a code inside this image.onload event:

image.onload = function () {
    //do other stuff that should be done right after image is loaded
}

But this is not my case. This is a signature of my function that is responsible for loading images:

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
}

So, I need to return! I must do it and I have no other chance. The reason I must follow this signature is that, this pattern is used by some external library function which looks like so:

style: function (feature) {
   var pattern = patternBuilder(feature.get("index"));
   var style = new ol.style.Style({
       fill: new ol.style.Fill({
           color: pattern
       })
   });
   return style;
}

So, even if I can change the logic of my patternBuilder function, I still can not change the external library function. This external function uses patternBuilder and returns a style variable itself. So, there is no room for callbacks.

like image 443
Jacobian Avatar asked Jul 25 '16 11:07

Jacobian


1 Answers

Here how this could work with promises

a simple wrapper to return image promises:

//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;
    });
}

and your 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];
}

and the function you use the pattern:

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
            })
        })
    })
}
like image 166
Thomas Avatar answered Oct 18 '22 14:10

Thomas