简体   繁体   中英

Why is my javascript Promise stuck as “pending”?

I have a complex SVG that is drawn to a canvas, and this task needs to complete before other objects are drawn. Here's a fiddle simulating this:

https://jsfiddle.net/1hucuLg9/1/

//draw svg
var promise = new Promise(function(){
  drawSwatch(document.getElementById("mySwatch")); 
  //not typo, canvas context is referenced inside this function due to xml complexity in this fiddle 
});
//draw image
promise.then(function(){
  ctx.drawImage(document.getElementById("myImg",0,0,150,150));
});

You'll note in the fiddle that only the SVG is drawn, not the other image afterwards. The Promise used to draw the SVG is stuck as pending ... even though the inner javascript is all executed. What's going on?

You should resolve the promise. Promise docs should be useful.

var promise = new Promise(function(resolve, reject){
  drawSwatch(document.getElementById("mySwatch"));
  resolve();
});
promise.then(function(){
  ctx.drawImage(document.getElementById("myImg",0,0,150,150));
});

If you want to add myImg only once the image inside drawSwatch has loaded - you can do this

var canvas = document.getElementById("myCanvas");
var ctx = canvas.getContext("2d");

//hard code variables for example
var vw=300, vh=200, x=20, y=50, w=250, h=50; rx=10, ry=5, bg="#fae", theta=15, midptX=100, midptY=120, blur=5;

//helper function to draw swatch objects
function drawSwatch(currentSwatch, resolve){ // extra parameter
    var data = '<svg xmlns="http://www.w3.org/2000/svg" width="'+vw+'" height="'+vh+'">'+
    '<defs>'+
    '<filter id="f1">'+
    '<feGaussianBlur in="SourceGraphic" stdDeviation="'+blur+'" />'+
    '</filter>'+
    '</defs>'+
    '<rect class="shape" x="0" y="0" width="'+w+'" height="'+h+'" rx="'+rx+'" ry="'+ry+'" transform="translate('+x+','+y+') rotate('+theta+','+midptX+','+midptY+')" fill="'+bg+'" filter="url(#f1)"></rect>'+
    '</svg>';

    //now draw the svg to canvas
    var svg_data = encodeURIComponent(data);
    // create a dataURI version
    var url = 'data:image/svg+xml; charset=utf8, ' + svg_data;
    var img = new Image();
    img.onload = function(){
      ctx.drawImage(img, 0, 0, vw, vh);
      resolve(); // call the passed in resolve function
    }
    img.src = url;
}

//draw svg
var promise = new Promise(function(resolve){ 
  drawSwatch(document.getElementById("mySwatch"), resolve); // call drawSwatch passing in the resolve function
});

promise.then(function(){
  ctx.drawImage(document.getElementById("myImg"),0,0,150,150);
});

added a second parameter to drawSwatch , which is the resolve function from the promise constructor function

Now the callback in promise.then wont be called until img.onload is fired

working fiddle - in the fiddle, instead of calling resolve directly, I've put it in a setTimout, to show that .then isn't executed until the promise is actually resolved

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM