优化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
相关产品推荐
相关产品推荐

