画布绘制函数以异步方式运行

Canvas drawing functions behaving in asynchronous way

本文关键字:异步 方式 运行 函数 布绘制 绘制      更新时间:2023-09-26

我在这里做的是覆盖整个网页,加载了画布层。现在,在该画布上,用户单击该单击将创建一个点。此时createDot()函数被调用。

createDot()内部,点被绘制到画布上,然后将屏幕截图请求发送到后台脚本。

现在的问题是,当我单击画布并截取屏幕截图时,屏幕截图中没有出现该点。

现在

奇怪的是,当我在同一画布上单击第二个点并且屏幕截图出现时,它现在有我单击的第一个点,而不是第二个点。

因此,正在发生的事情是屏幕截图没有捕获当前点,而只是捕获以前的点。

我检查了画布绘图功能是否全部阻塞,因此在绘图完成之前无法将请求发送到后台脚本。我也通过登录到控制台来确认这一点。

内容脚本:

function createDot(canvas) {
    var context = canvas.getContext("2d");
    var canvasOffset = $("#canvas").offset();
    var offsetX = canvasOffset.left;
    var offsetY = canvasOffset.top;
    var pointX , pointY;
    var point_X,point_Y;
    function handleMouseDown(e) {
        //coordinates of the click in dom.
        pointX = parseInt(e.pageX - offsetX);
        pointY = parseInt(e.pageY - offsetY);
        //making the dot
        var radius = 10;
        context.beginPath();
        context.arc(pointX, pointY, radius, 0, 2 * Math.PI);
        context.fillStyle = 'red';
        context.fill();
        context.lineWidth = 2;
        context.strokeStyle = '#003300';
        context.stroke();
        console.log("drawn everything");
        takeDotScreenshot();  //gets called when the canvas has finished its job of drawing.
    }
    $("#canvas").mousedown(function (e) {
        handleMouseDown(e);
    });
}
function takeDotScreenshot() {
    console.log("sending request to Background script");
    chrome.runtime.sendMessage({"capture":true},function(response) {
        var img_src=response.screenshot;
    });
    //logic for using that screenshot and appending it on to the content page...
}

后台脚本:

chrome.runtime.onMessage.addListener(function(request,sender,sendResponse) {
    if(request.capture) {
        chrome.tabs.query({active: true, currentWindow: true}, function(tabs) {
            chrome.tabs.captureVisibleTab(null, {}, function(dataUrl) {
                if(dataUrl) {
                    sendResponse({"screenshot":dataUrl});           
                }
            });
        });
    }
    return true;
});

更新:

如果我使用 setTimeout 1ms 来调用 takeDotScreenshot 函数,一切正常。为什么!

setTimeout(takeDotScreenshot, 1);

有一个非常详细,很好的答案,为什么setTimeout在这里有帮助:https://stackoverflow.com/a/4575011/10574621

画布的 DOM-Update-事件(实际上使点可见)可能位于截图事件后面,即使画布从 stroke() 事件中接收到所需的所有数据也是如此。

屏幕截图是用户可以看到的内容的快照。在呈现函数中时,画布不会显示,直到执行堆栈为空(从函数中一直返回)

根据渲染方式(使用 requestAnimationFrame 或直接从鼠标、键盘、计时器事件),画布仍需要一些时间才能呈现给显示器。

将超时设置为零时,可以将调用添加到在画布呈现给显示器之前运行的调用堆栈。您运行的任何代码都将阻止页面,从而阻止显示画布,从而没有屏幕截图。

我会将渲染的超时设置为捕获至少 17 毫秒(略高于 60fps)。没有人能注意到这种延迟,但有足够的时间将画布呈现给显示器