为什么Promise的resolve函数在React中执行两次,浏览器控制台却正常?
问题原因
这个现象是React 18及以上版本的开发环境严格模式导致的,和你的代码逻辑本身无关。
- React 18默认给开发环境开启了严格模式(通常是在入口文件用
<React.StrictMode>包裹根组件实现),会故意触发组件两次渲染、两次副作用执行,目的是帮开发者提前暴露没有正确清理副作用、依赖声明错误的潜在问题,生产环境下不会有该表现。 - 你的代码中
getResult是直接写在组件顶层的,组件每渲染一次就会完整执行一次组件内的所有顶层代码,getResult就会被调用一次,对应的myFun也会执行一次,内部会注册两套定时器,3秒后自然会打印两次resolve。 - 你在浏览器控制台直接运行代码时,没有React严格模式的机制,代码只会执行一次,所以只会打印一次。
验证方法
你可以临时移除入口文件的<React.StrictMode>包裹,再运行开发环境,就能看到resolve只会打印一次,但不建议长期关闭严格模式,它能有效帮你规避很多React常见问题。
正确修复方案
不要把带副作用的逻辑直接放在组件顶层执行,应该放到useEffect钩子中,并且做好副作用清理,避免重复执行和内存泄漏,参考修改后的代码:
import { useEffect } from 'react'; export const Wei = () => { const myFun = () => { let state = false; const timer1 = setTimeout(() => { state = true; }, 2000); const promise = new Promise((resolve, reject) => { const timer2 = setTimeout(() => { if (state) { console.log("resolve"); resolve("State is true"); } else { reject("State is false"); } }, 3000); }); // 返回定时器清理函数 return { promise, clear: () => { clearTimeout(timer1); clearTimeout(timer2); } } }; console.log("render"); useEffect(() => { const { promise, clear } = myFun(); const getResult = async () => { console.log("before"); try { const res = await promise; console.log("after"); console.log(res); } catch (err) { console.log(err); } }; getResult(); // 组件卸载/依赖更新时清理定时器 return clear; }, []); // 空依赖保证仅在组件挂载时触发一次逻辑 return <div>1</div>; };
修改后就算严格模式下触发两次useEffect执行,也会在第一次执行结束后调用清理函数清空上一次注册的定时器,就不会出现重复打印的问题。
内容的提问来源于stack exchange,提问作者wei wang
相关产品推荐
相关产品推荐

