You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

优化Canvas连续鼠标操作:寻找JavaScript高效延迟方案

问题描述

我有一个绘制了不同对象的Canvas,需要拖拽其中的对象,但无法直接访问这些元素,因此采用图像搜索算法实现交互。当拖拽操作的时间间隔过近时会失效,推测是操作重叠导致的。

原代码通过在每次拖拽后固定等待1000毫秒实现了三个对象的移动,但固定等待时间无法适配不同设备的资源情况,且需要尽可能提升执行速度,不能长时间等待。尝试用Promise改写代码时误解了其功能,导致操作无间隔重叠,往往仅执行一次,现寻求解决方案。


原代码

var canvasElement = document.querySelector('body > canvas');

function simulateMouseEvent(eventType, x, y) {
    canvasElement.dispatchEvent(new MouseEvent(eventType, { clientX: x, clientY: y }));
}

function performClickAndDragAction(FoundX, x_temp, y_temp) {
    simulateMouseEvent('mousedown', FoundX, 626);
    simulateMouseEvent('mousemove', x_temp, y_temp);
    simulateMouseEvent('mouseup', x_temp, y_temp);
}

if (canvasElement) {
  
    performClickAndDragAction(67, 47, 591);
    
    setTimeout(() => {
        performClickAndDragAction(186, 160, 591);

        setTimeout(() => {
            performClickAndDragAction(305, 255, 591);
        }, 1000); 

    }, 1000); 
} else {
    alert('No canvas.');
}

Promise改写后的问题代码

var canvasElement = document.querySelector('body > canvas');

function simulateMouseEvent(eventType,x, y) {
    return new Promise((resolve, reject) => {
        canvasElement.dispatchEvent(new MouseEvent(eventType, { clientX: x, clientY: y }));
        resolve();
    });
}

function performClickAndDragAction(FoundX, x_temp, y_temp) {
    return simulateMouseEvent('mousedown', FoundX, 626)
        .then(() => simulateMouseEvent('mousemove', x_temp, y_temp))
        .then(() => simulateMouseEvent('mouseup', x_temp, y_temp));
}

if (canvasElement) {
    performClickAndDragAction(67, 47, 591)
        .then(() => performClickAndDragAction(186, 160, 591))
        .then(() => performClickAndDragAction(305, 255, 591))
        .catch((error) => {
            console.error('Error: ', error);
        });
} else {
    alert('No canvas.');
}

解决方案

问题根源

Promise版本的核心问题在于simulateMouseEvent同步触发事件后立刻resolve,没有给Canvas的拖拽逻辑留处理时间,导致三次拖拽操作几乎同时执行,系统无法区分处理。

方案一:带可配置间隔的Promise串联

通过给每个拖拽操作后增加可控的短等待,既避免操作重叠,又比固定1000毫秒更灵活,可根据设备性能调整时长:

var canvasElement = document.querySelector('body > canvas');

function simulateMouseEvent(eventType, x, y) {
    canvasElement.dispatchEvent(new MouseEvent(eventType, { clientX: x, clientY: y }));
}

// 封装等待函数,返回Promise
function wait(ms) {
    return new Promise(resolve => setTimeout(resolve, ms));
}

function performClickAndDragAction(FoundX, x_temp, y_temp) {
    simulateMouseEvent('mousedown', FoundX, 626);
    simulateMouseEvent('mousemove', x_temp, y_temp);
    simulateMouseEvent('mouseup', x_temp, y_temp);
    // 拖拽完成后等待指定时长,可按需调整(比如200-500ms)
    return wait(300);
}

if (canvasElement) {
    performClickAndDragAction(67, 47, 591)
        .then(() => performClickAndDragAction(186, 160, 591))
        .then(() => performClickAndDragAction(305, 255, 591))
        .catch(error => console.error('Error: ', error));
} else {
    alert('No canvas.');
}

方案二:自适应状态检测(更高效)

如果你的图像搜索算法可以检测对象是否移动到目标位置,可通过检查操作完成状态来触发下一个拖拽,完全无需固定等待:

var canvasElement = document.querySelector('body > canvas');

function simulateMouseEvent(eventType, x, y) {
    canvasElement.dispatchEvent(new MouseEvent(eventType, { clientX: x, clientY: y }));
}

// 等待条件满足的工具函数
function waitForCondition(conditionCheck, interval = 50, timeout = 5000) {
    return new Promise((resolve, reject) => {
        const startTime = Date.now();
        const check = () => {
            if (conditionCheck()) {
                resolve();
            } else if (Date.now() - startTime > timeout) {
                reject(new Error('等待条件超时'));
            } else {
                setTimeout(check, interval);
            }
        };
        check();
    });
}

function performClickAndDragAction(FoundX, x_target, y_target) {
    simulateMouseEvent('mousedown', FoundX, 626);
    simulateMouseEvent('mousemove', x_target, y_target);
    simulateMouseEvent('mouseup', x_target, y_target);
    
    // 替换为你的图像搜索检测逻辑:验证对象是否已到达目标位置
    return waitForCondition(() => {
        // 示例:return imageSearchVerifyPosition(x_target, y_target);
        // 若暂时无法实现图像检测,可先用短等待兜底
        return true;
    });
}

if (canvasElement) {
    performClickAndDragAction(67, 47, 591)
        .then(() => performClickAndDragAction(186, 160, 591))
        .then(() => performClickAndDragAction(305, 255, 591))
        .catch(error => console.error('Error: ', error));
} else {
    alert('No canvas.');
}

内容的提问来源于stack exchange,提问作者Manuel Vencato

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 22:47:07