多线程无法为您解决这个问题。如前所述,Web Worker 是有限的,并且在这种情况下不会增加任何好处,因为这需要访问 DOM 等。(您可以使用它们来处理使用可转移对象的像素,即类型化数组,但是您必须在处理后将它们通过管道传回您的主 JS 线程,这样您才能走得更远)。
不过好消息,您可以同时绘制两幅不同的画。我假设您使用画布来实现这一点。
只需创建两个重叠的画布,并将您的本地鼠标/触摸移动提供给其中一个画布,同时通过您的网络套接字将数据提供给另一个画布。
另一种方法是以原子方式绘制每个片段 - 对于每次鼠标移动和通过 Web 套接字接收的表示移动的每个数据(您可能需要在此处迭代),例如:
ctx.beginPath(); /// reset path for this segment
ctx.moveTo(oldX, oldY); /// of current client/user
ctx.lineTo(x, y); /// current position
ctx.strokeStyle = currentColor; /// the one drawing this line
ctx.stroke();
(oldX/Y 第一次会被鼠标按下事件初始化)。
以分段方式执行此操作可以让两者同时绘制,尽管它对性能的要求更高。如果线条的顺序不重要,我个人会选择分层画布解决方案。由于您的解决方案将使用事件,因此它将是异步的,并且会处理一个在这里应该可以正常工作的事件队列。
只需设置一些数组来保存每个用户的数据(旧位置、样式等),这样您就可以为当前用户/客户端使用 ID/索引。
一些伪代码对分段方法进行简单概述:
var oldX = [],
oldY = [],
currentColor = [], ...;
...set up clients, arrays, mousedown/up etc.
canvas.onmousemove = function(e) {
var pos = getMousePos ...
if (isDrawing) drawSegment(0, pos.x, pos.y); /// f.ex. client 0 = local
}
function handleSocketData() {
... get x/y from data stream
drawSegment(1, x, y); /// f.ex. client 1 = web socket
}
function drawSegment(client, x, y) {
ctx.beginPath();
ctx.moveTo(oldX[client], oldY[client]);
ctx.lineTo(x, y);
ctx.strokeStyle = currentColor[client];
ctx.stroke();
oldX[client] = x;
oldY[client] = y;
}
这当然是简化的。您需要将每个点存储在具有与绘制时相同的状态详细信息的点数组中,以便能够在清除后重新绘制画布,处理套接字上的多个段等等,但我认为它给人的印象是如何实现该方法的核心原理。
希望这会有所帮助!