React Native中Spinner配合循环计算无法正常工作问题求助
React Native加载指示器(Spinner)不显示问题
我用React Native开发应用,现在实现Spinner功能时遇到问题。我有个calculatorLoops函数,里面是嵌套循环做数值计算,需求是计算过程中显示Spinner,循环结束后隐藏。但把函数设为async后达不到预期效果,加了await fetch("https://www.google.com/")后Spinner能正常显示,用Promise替代fetch却没用,而且我根本不需要这个fetch请求。
相关代码:
const calculatorLoops = async (column: string) => { await fetch("https://www.google.com/"); let howManyLoop = 0; let isWon = false; let founds; while (!isWon) { founds = compareNumbers(user.lotteryNumbers[column], { lotteryNumbers: createNumbers() }); howManyLoop++; if (founds.cnt === loopNum) isWon = true; } setFoundNum({ foundCnt: howManyLoop, foundNumbers: founds.foundsNumbers }); }; const handlePress = async (column: string) => { setLoading(true); await calculatorLoops(column); setLoading(false); }; // 尝试用Promise的版本 const calculatorLoops = async (column: string) => { return new Promise((res, rej) => { let howManyLoop = 0; let isWon = false; let founds; while (!isWon) { founds = compareNumbers(user.lotteryNumbers[column], { lotteryNumbers: createNumbers() }); howManyLoop++; if (founds.cnt === loopNum) isWon = true; } res(setFoundNum({ foundCnt: howManyLoop, foundNumbers: founds.foundsNumbers })); }); };
问题原因
JavaScript是单线程的,你的循环计算是同步阻塞操作——就算包在Promise里,整个循环还是会一次性占满主线程,根本没给React更新UI(显示Spinner)的机会。而fetch是异步网络请求,会把线程交还给React,让UI有时间更新,之后才执行后续的循环。
解决方案
要把同步计算拆成小块,让主线程有间隙处理UI更新。可以用setTimeout或者requestAnimationFrame把循环的每一步(或每几步)放到下一个事件循环里执行。
修改后的代码示例
const calculatorLoops = async (column: string) => { let howManyLoop = 0; let isWon = false; let founds; // 封装单次计算为异步步骤 const loopStep = () => { return new Promise(resolve => { // 用setTimeout让出主线程,给UI更新留时间 setTimeout(() => { founds = compareNumbers(user.lotteryNumbers[column], { lotteryNumbers: createNumbers() }); howManyLoop++; isWon = founds.cnt === loopNum; resolve(isWon); }, 0); }); }; // 异步循环,每次await后让出线程 while (!isWon) { await loopStep(); } setFoundNum({ foundCnt: howManyLoop, foundNumbers: founds.foundsNumbers }); }; const handlePress = async (column: string) => { setLoading(true); await calculatorLoops(column); setLoading(false); };
优化建议
- 如果单次计算很快,可以一次处理多步循环(比如一次跑50次计算再await),这样既保证UI响应,又不会因为频繁切换线程拖慢计算速度:
const loopStep = () => { return new Promise(resolve => { setTimeout(() => { // 一次跑50次计算 for (let i = 0; i < 50; i++) { if (isWon) break; founds = compareNumbers(user.lotteryNumbers[column], { lotteryNumbers: createNumbers() }); howManyLoop++; isWon = founds.cnt === loopNum; } resolve(isWon); }, 0); }); };
内容的提问来源于stack exchange,提问作者Lior98
相关产品推荐
相关产品推荐

