React中Playwright缓存失效:重复请求URL无法读取缓存求解
React中使用Playwright缓存HTML未命中的问题
我在React应用中运行Playwright,目标是直接返回缓存结果。以下代码可设置和获取缓存,但同一URL再次请求时无法命中缓存,请问我遗漏了什么?
const { chromium } = require('playwright'); const LRU = require('lru-cache'); const cache = new LRU({ max: 500, // 缓存最大条目数 ttl: 86400 // 缓存条目有效期(毫秒) }); async function fetchHTML(url) { const browser = await chromium.launch(); const context = await browser.newContext(); const page = await context.newPage(); page.setDefaultTimeout(10000); // 检查URL是否在缓存中 let html = cache.get(url); if (html) { // 这里从未执行过 😞 console.log('从缓存获取HTML'); } else { await page.goto(url); // html = await page.content(); html = await page.evaluate(() => document.body.innerHTML); console.log('为' + url + '设置缓存'); cache.set(url, html); let cachedHtml = cache.get(url); // 😄 这里却能正常获取 🤷 console.log('缓存HTML长度: ' + cachedHtml.length); // 返回: 缓存HTML长度: 1234 } await browser.close(); return html; } let url = 'https://example.com'; let html = fetchHTML(url); // 成功获取! console.log(html.length); // 返回: 1234 // 但缓存生效了吗? let cachedHtml = fetchHTML(url); // 这次还是重新获取,而非从缓存读取。为什么? console.log(cachedHtml.length);
问题根源
- 异步函数调用未用await:
fetchHTML是异步函数,直接调用会返回Promise对象而非实际HTML内容。两次调用几乎同时发起,第一次的缓存写入逻辑还未执行完成,第二次就已经做了缓存检查,自然无法命中。 - 错误的日志输出:你看到的
html.length实际是打印Promise对象的属性,并非HTML内容的长度,这会误导你以为已经拿到了真实结果。
修复方案
1. 正确使用await调用异步函数
将调用逻辑放在async函数中,用await等待异步操作完成,确保第一次缓存写入完成后再执行第二次请求:
async function run() { let url = 'https://example.com'; // 第一次请求,写入缓存 let html = await fetchHTML(url); console.log('第一次获取的HTML长度:', html.length); // 第二次请求,命中缓存 let cachedHtml = await fetchHTML(url); console.log('第二次获取的HTML长度:', cachedHtml.length); } // 执行主函数 run();
2. 优化浏览器实例复用(可选但关键)
当前代码每次调用fetchHTML都会启动新浏览器,性能极低且浪费资源。可以将浏览器实例初始化移到函数外部,复用上下文:
const { chromium } = require('playwright'); const LRU = require('lru-cache'); const cache = new LRU({ max: 500, ttl: 86400 }); // 提前初始化浏览器,复用实例 let browser; async function initBrowser() { if (!browser) { browser = await chromium.launch(); } return browser; } async function fetchHTML(url) { let html = cache.get(url); if (html) { console.log('从缓存获取HTML'); return html; } const browser = await initBrowser(); const context = await browser.newContext(); const page = await context.newPage(); page.setDefaultTimeout(10000); await page.goto(url); html = await page.evaluate(() => document.body.innerHTML); console.log('为' + url + '设置缓存'); cache.set(url, html); await context.close(); // 只关闭上下文,保留浏览器实例 return html; } // 主函数 async function run() { let url = 'https://example.com'; let html = await fetchHTML(url); console.log('第一次HTML长度:', html.length); let cachedHtml = await fetchHTML(url); console.log('第二次HTML长度:', cachedHtml.length); // 程序结束时关闭浏览器 await browser.close(); } run();
验证效果
修复后第二次调用fetchHTML会触发从缓存获取HTML的日志,说明缓存命中成功。
内容的提问来源于stack exchange,提问作者Ryan
相关产品推荐
相关产品推荐

