如何确保复杂画布操作的正确执行顺序

时间:2015-12-17 12:55:49

标签: javascript dom canvas

我有一些代码可以将特定的DOM元素呈现给画布,就像截取屏幕截图一样。 (它是为特定DOM结构构建的自定义代码,作为图形编辑游戏的一部分,而不是像rasterHTML.js这样的通用库)

代码流程非常具有程序性:

  1. 获取A类的一些DOM元素并将它们绘制到画布
  2. 获取B类的一些DOM元素并将它们绘制到画布
  3. 问题在于步骤1与步骤2相比非常密集,并且在步骤2之前没有完成绘制,拧紧图层(实际上我有几个画布同时做几件事,画布是不幸的是,在完成所有绘图之前调整了大小)。我试图在这个小提琴中复制这个:https://jsfiddle.net/1hucuLg9/

    在伪代码中:

    context.drawComplexSVG(); // slow
    context.drawSimpleImage(); //fast
    //canvas now has an SVG drawn on top of an image, not underneath.
    

    我已经看到很多setTimeout例子试图让一个功能一个接一个地执行,但对我来说这似乎是一个黑客攻击...理想情况下我不会&#39 ; t想要延迟执行,只需按严格的顺序执行所有操作。我也看到了postMessage想法实现这一点的想法,但我不知道你如何将信息传递给自己。在继续之前,确保函数/行完全执行的正确方法是什么(或者在我的情况下,画布是完全更新的 - 它是一样的吗?)?

2 个答案:

答案 0 :(得分:1)

"获取一些DOM元素"应该是同步的,不需要任何复杂的代码来处理排序绘制操作。

你在小提琴中遇到的问题是你动态加载一些图像来绘制 - 和for those, you need to wait,这使得操作异步。

承诺是为了你的救援,但你必须正确使用它们。只需像你在自己的回答中那样立即调用resolve,就可以确保某些异步,但这并不比setTimeout方法脆弱。相反,你应该始终在异步的核心创建承诺,在你的情况下加载图像:

function loadImage(src) {
    return new Promise(resolve, reject) {
        var img = new Image();
        img.onload = function(){ resolve(img); };
        img.onerror = reject;
        img.src = src;
    });
}

以便您可以在画布绘图代码中使用它:

function drawSwatches(currentSwatch) {
    var data = …;
    var url = 'data:image/svg+xml; charset=utf8, ' + encodeURIComponent(data);

    return loadImage(url).then(function(img) {
        ctx.drawImage(img, 0, 0, vw, vh);
    });
}

然后恰当地链接这些:

var swatches = Array.from(document.getElementsByClassName("swatch"));
swatches.reduce(function(promise, swatch) {
    return promise.then(function() {
        return drawSwatches(swatch);
    });
}, Promise.resolve()).then(function() {
    var otherObjects =  document.getElementsByClassName("otherObjects");
    for (var i=0; i<otherObjects.length; i++) {
        drawOtherObjects(otherObjects[i], 0, 0, 100, 100);
    }
});

答案 1 :(得分:0)

好吧,这似乎可以完成工作:

var promise = new Promise(function(resolve){
  context.drawComplexSVG();
  resolve();
}
promise.then(function(){
  context.drawSimpleImage();
}