React Native中useEffect内Promise.race未解析的渐进式图片加载问题
渐进式图片加载器Promise.race未解析问题修复
你的代码存在几个关键问题,直接导致了Promise.race后续逻辑不执行,以下是排查和修复方案:
1. 语法错误:if语句未闭合
handleRace函数中的if块漏掉了闭合的},JavaScript引擎解析失败,整个函数无法正常执行,自然不会输出后续日志。修复后:
async function handleRace() { const raceResult = await Promise.race([checkCache(), downloadAndSetSmallAndMediumImages()]); console.log('here', raceResult); if (isCacheChecked && !cacheHit) { console.log('cache miss'); await downloadAndSetSmallAndMediumImages(); await handleFinalBigImageDownloadAndSet(); } else { // 补上缺失的闭合花括号 console.log('cache hit'); } }
2. 缺少错误捕获逻辑
Promise.race中任意一个Promise发生reject时,整个race会直接抛出错误,而你的代码没有添加错误捕获,错误会被静默(或触发未捕获Promise rejection),导致代码中断。给handleRace加上错误处理:
async function handleRace() { try { const raceResult = await Promise.race([checkCache(), downloadAndSetSmallAndMediumImages()]); console.log('here', raceResult); if (isCacheChecked && !cacheHit) { console.log('cache miss'); await downloadAndSetSmallAndMediumImages(); await handleFinalBigImageDownloadAndSet(); } else { console.log('cache hit'); } } catch (err) { console.error('加载流程出错:', err); // 可在此添加UI错误提示逻辑 } }
3. 状态变量管理问题
isCacheChecked和cacheHit如果是普通变量,组件重新渲染时会被重置,且async函数会捕获变量的旧值,导致逻辑判断错误。改用React的useState管理这些状态:
const [cacheHit, setCacheHit] = useState(false); const [isCacheChecked, setIsCacheChecked] = useState(false); // 在checkCache中更新状态 async function checkCache() { // 缓存检查逻辑,示例使用Cache API const cache = await caches.open('image-cache'); const cachedResponse = await cache.match(imageSource); if (cachedResponse) { const blob = await cachedResponse.blob(); setImageSource(URL.createObjectURL(blob)); setCacheHit(true); } setIsCacheChecked(true); console.log('缓存检查完成'); return !!cachedResponse; }
4. 函数定义语法错误
你贴出的代码中三个async函数使用了async function checkCache();这种带分号的错误写法,函数声明不能带分号,改为标准定义形式:
async function checkCache() { // 具体实现逻辑 }
额外优化点
- 缓存未命中时无需重复调用
downloadAndSetSmallAndMediumImages,Promise.race已经在并行执行该函数,重复调用会导致冗余下载。 - 在useEffect的清理函数中,revoke通过
URL.createObjectURL创建的blob链接,避免内存泄漏:
return () => { if (imageSource?.startsWith('blob:')) { URL.revokeObjectURL(imageSource); } };
内容的提问来源于stack exchange,提问作者IntiM
相关产品推荐
相关产品推荐

