使用Playwright实现多用户并行执行UI检查
Playwright多用户并行UI检查实现方案
一、任务拆分逻辑
- 按用户数量均分数据:5000条数据分给3个用户,前两个用户各处理1666条,第三个用户处理1668条(
5000 - 1666*2 = 1668) - 用通用chunk函数拆分数组,适配任意用户数量:
function splitArrayIntoChunks(arr, chunkCount) { const chunks = []; const chunkSize = Math.ceil(arr.length / chunkCount); for (let i = 0; i < arr.length; i += chunkSize) { chunks.push(arr.slice(i, i + chunkSize)); } return chunks; }
二、多用户隔离实现
使用Playwright的browser.newContext()创建完全隔离的浏览器上下文,每个上下文对应一个独立用户,拥有专属会话、Cookie和本地存储,完美模拟多用户并发交互。
三、并行执行与任务监控
- 用
Promise.all并行启动所有用户的检查任务 - 每个任务内部维护进度统计(已处理数、成功数、失败数),实时输出日志
- 任务结束后汇总所有结果,生成全局报告
四、完整示例代码
const { chromium } = require('playwright'); // 模拟API获取5000条数据(替换为你的API请求逻辑) async function fetchApiData() { return Array.from({ length: 5000 }, (_, idx) => ({ id: idx + 1, content: `Item ${idx + 1}` })); } // 单条数据UI检查逻辑(替换成你已实现的脚本) async function checkSingleItem(page, item) { try { await page.goto(`https://your-target-url.com/item/${item.id}`); await page.waitForSelector(`text=${item.content}`); return { itemId: item.id, status: 'success', error: null }; } catch (err) { return { itemId: item.id, status: 'failed', error: err.message }; } } // 单个用户的任务执行函数 async function runUserTask(browser, userDataChunk, userId) { const context = await browser.newContext(); const page = await context.newPage(); // 可添加用户专属登录逻辑(不同用户用不同账号) // await page.goto('/login'); // await page.fill('#username', `user${userId}`); // await page.fill('#password', `pass${userId}`); // await page.click('text=登录'); const stats = { processed: 0, success: 0, failed: 0, results: [] }; for (const item of userDataChunk) { const result = await checkSingleItem(page, item); stats.processed++; stats[result.status]++; stats.results.push(result); // 实时输出进度 console.log(`用户${userId} - 已处理${stats.processed}/${userDataChunk.length} | 成功:${stats.success} | 失败:${stats.failed}`); } await context.close(); return { userId, stats }; } async function main() { // 1. 获取API数据 const apiData = await fetchApiData(); // 2. 拆分成3份任务 const dataChunks = splitArrayIntoChunks(apiData, 3); // 3. 启动浏览器(调试时可设headless:false) const browser = await chromium.launch({ headless: true }); // 4. 并行执行所有用户任务 const userTasks = dataChunks.map((chunk, idx) => runUserTask(browser, chunk, idx + 1)); const allResults = await Promise.all(userTasks); // 5. 关闭浏览器 await browser.close(); // 6. 汇总输出最终结果 console.log('\n=== 最终汇总 ==='); let totalProcessed = 0, totalSuccess = 0, totalFailed = 0; allResults.forEach(({ userId, stats }) => { console.log(`用户${userId}: 总处理${stats.processed} | 成功${stats.success} | 失败${stats.failed}`); totalProcessed += stats.processed; totalSuccess += stats.success; totalFailed += stats.failed; }); console.log(`全局统计: 总处理${totalProcessed} | 成功${totalSuccess} | 失败${totalFailed}`); // 可选:导出失败结果到文件 // const failedItems = allResults.flatMap(res => res.stats.results.filter(r => r.status === 'failed')); // require('fs').writeFileSync('失败项列表.json', JSON.stringify(failedItems, null, 2)); } // 通用数组拆分函数 function splitArrayIntoChunks(arr, chunkCount) { const chunks = []; const chunkSize = Math.ceil(arr.length / chunkCount); for (let i = 0; i < arr.length; i += chunkSize) { chunks.push(arr.slice(i, i + chunkSize)); } return chunks; } main().catch(err => console.error('主流程失败:', err));
五、关键注意事项
- 资源隔离:每个用户使用独立上下文,避免会话、Cookie冲突
- 错误隔离:单条检查失败不中断整个用户任务,通过内部捕获错误保障流程持续
- 性能控制:数据量过大时可借助
p-limit库限制并发数,避免浏览器资源耗尽 - 监控扩展:可接入日志库(如winston)或CLI进度条工具,提升监控可视化体验
- 用户差异化:不同用户的登录、权限逻辑可在
runUserTask中单独实现
内容的提问来源于stack exchange,提问作者OkanKarahan
相关产品推荐
相关产品推荐

