使用WebDriver+JavaScript时forEach循环输入变量异常求助
搞定WebDriver异步遍历的顺序问题
嘿,我一眼就看出你踩了个经典坑——forEach和async/await压根儿不对付!这就是为什么你的操作顺序完全乱掉的原因。
问题根源
forEach是同步遍历函数,它不会管你回调里的异步操作有没有完成。当你在forEach里写await时,它会一口气把所有的sendKeys和click都触发,这些异步操作会在后台同时跑,WebDriver自然就乱了阵脚——要么把所有内容一次性塞进输入框,要么点了保存才开始输入,完全不是你要的逐个执行效果。
最简单的修复:换成for...of循环
for...of是支持异步等待的遍历方式,它会老老实实地等上一个异步操作完成,再执行下一个,完美匹配你的需求:
const queries = ["1", "2", "3"]; for (const query of queries) { // 等待输入完成 await driver.findElement(By.css(Input)).sendKeys(query); // 等待保存点击完成 await driver.findElement(By.css(save)).click(); // 额外提示:如果保存后页面会刷新或者输入框重新渲染,最好加个等待 // 比如等输入框重新可交互,避免后续操作报错 // await driver.wait(until.elementIsEnabled(driver.findElement(By.css(Input))), 5000); }
为什么forEach不行?再啰嗦两句
举个简单例子:forEach就像你给3个同事同时发消息让他们做任务,不管他们有没有做完,你都继续发下一条;而for...of是你等第一个同事做完,再给第二个发消息,顺序绝对不会乱。你的WebDriver操作都是异步的,必须用能等待的遍历方式才行。
另一种方案:用reduce串行执行
如果你更喜欢数组方法,也可以用reduce来串起所有异步操作,不过可读性不如for...of:
["1", "2", "3"].reduce(async (previousTask, query) => { // 先等上一个任务完成 await previousTask; // 再执行当前任务 await driver.findElement(By.css(Input)).sendKeys(query); await driver.findElement(By.css(save)).click(); }, Promise.resolve()); // 初始值是一个已完成的Promise
最后提醒下:每次保存后如果页面有变化,一定要确保元素是最新的,或者加个显式等待,不然容易碰到“过时元素”的错误哦!
内容的提问来源于stack exchange,提问作者Mordi Riggs
相关产品推荐
相关产品推荐

