1、问题源码:
<p>要使用的图像:</p>
<img id="tulip" src="/i/eg_tulip.jpg" alt="The Tulip" />
<p>画布:</p>
<canvas id="myCanvas" width="500" height="300" style="border:1px solid #d3d3d3;background:#ffffff;">
Your browser does not support the HTML5 canvas tag.
</canvas>
<script>
var c=document.getElementById("myCanvas");
var ctx=c.getContext("2d");
var img=document.getElementById("tulip");
ctx.drawImage(img,10,10);
</script>
2、解决办法:
在
ctx.drawImage(img,10,10);
外面套一层:
img.onload=function(){
ctx.drawImage(img,10,10);
}
3、原因分析:
图片的加载是异步的,它会在自己后面的非异步代码执行完之后,再开始执行自己
异步猛一看有点并发的感觉,其实还是排队,且还是排的原来那条队,时间并没有被节省,只不过它会在轮到自己时,放弃自己的位置,主动站到非异步的代码队尾,非异步的都执行完再轮到自己时,才开始执行自己的,它后面其他的异步对象也是如此,不过后面异步的对象会等前面的异步执行了之后再执行,不过不会等待前面的异步执行完才执行。有点Gentleman的赶脚!
js中所有事件都是异步的,onload也是,onload的异步在图片异步之后,所以onload会在图片加载之后执行,同时onload除了异步之外,它还是个事件,也就是图片加载了之后才会触发,所以使用onload是百分百可以看到图片
同时如果不使用onload,使用
setTimeout(function(){
ctx.drawImage(img,10,10);
},0);
也会看到图片被绘制出来,不过不是稳定的,偶尔看不到。原因就是
setTimeout
制造了一个异步,即使等待时间是0,这就意味着它成了一个图片加载异步之后的一个异步,图片加载先执行,它后执行,假如图片加载的快,它就绘制成功,慢了,它就失败。如果没有了
setTimeout
就百分百失败,因为绘制图片的代码所在的子队列在图片异步之前,图片会等到它执行完了,才刚刚开始自己的加载工作
PS:
1、火狐似乎是个特例,它不用那些麻烦事,直接w3school拷贝下来的实例代码,刷新下就可以正常访问了,这是为啥?
2、w3school上拷贝的代码虽然本地不能绘制成功,可是在线,在它的实例执行页面看效果确实正常的,这怎么解释呢?
有路过的大神,还请赐教~