背景:
React代码如下
import { useState } from 'react';export default function App() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); setTimeout(() => { console.log(count, 'end'); // 还是 0! }, 5000); } return ( <> <button onClick={handleClick}>+1</button> <span>{count}</span> </> );}
setCount的更新是异步更新的,setTimeout也是异步的,为什么点击,console.log打印的是0,而不是1。
尝试:
尝试用普通js函数进行比较,js代码如下
function outerFunction() { let count = 0; function innerFunction() { console.log(count); } count = 1; // 将count更新为1 setTimeout(innerFunction, 5000); count = 2; } outerFunction();
console.log打印的是最新的值2。
疑问: 两段代码的打印结果不同,是什么原因呢?
当你setState
时,组件会rerender
,所谓rerender
其实就是App
这个function
重新执行了一次,重新执行时你通过useState
这个hook
取到是最新值,但是你上一次App
的函数调用中的setTimeout
的回调中的count
因为闭包的关系访问的仍然是当时的值,转换成下面这种更接近:
var value;function useState(val) { return [value ??= val, v => { value = v; App(); }]}function App() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); setTimeout(() => { console.log(count, 'end'); // 还是 0! }, 5000); } console.log('render', count) return { onClick: handleClick, }} App().onClick()
首先这里是const,不会改变的。是let的话也不会改变,除非是一个object,才可能会改变。
现在它可以输出1了。
import { useState } from 'react';function Count() { const [count, setCount] = useState({ count: 0 }); const handleClick = () => { setCount((pre) => { pre.count += 1; return pre; }); setTimeout(() => { console.log(count.count, 'end'); // 还是 0! }, 5000); }; return ( <> <button onClick={handleClick}>+1</button> <span>{count.count}</span> </> );}export default Count;
setTimeout(() => { console.log(count, 'end'); // 还是 0!}, 5000);
你可以把react
组件的每次渲染理解为生成了一个平行宇宙,所以代码里面的定时器,是在上一个渲染生成的平行宇宙中,输出的count
也是那个平行宇宙中的值。
在React中,useState
的更新是异步的,这意味着当你调用setCount
函数时,count
的值不会立即改变。相反,React会等待当前的渲染周期完成,然后在下一个渲染周期中更新count
的值。
在你的React代码示例中,当你点击按钮时,setCount
函数会被调用,count
的值会被计划在下一个渲染周期中更新。然后,setTimeout
函数会在5秒后执行,此时count
的值还没有被更新,所以console.log
打印的仍然是旧的值0。
而在你的JavaScript代码示例中,当你调用count = 1
和count = 2
时,count
的值会立即改变,所以在5秒后执行innerFunction
时,console.log
打印的是最新的值2。
为了解决这个问题,你可以在setTimeout
的回调函数中直接使用setCount
函数来获取最新的count
值。这样,无论count
何时更新,setTimeout
的回调函数中都能获取到最新的值。以下是修改后的React代码示例:
import { useState } from 'react';export default function App() { const [count, setCount] = useState(0); const handleClick = () => { setCount(count + 1); setTimeout(() => { console.log(count, 'end'); // 使用setCount获取最新的值 }, 5000); } return ( <> <button onClick={handleClick}>+1</button> <span>{count}</span> </> );}
在这个修改后的示例中,setTimeout
的回调函数中使用了count
而不是setCount
来获取最新的值。当count
的值更新时,setTimeout
的回调函数中也会获取到最新的值,因此console.log
会打印出正确的值。
打印结果: 打印走到了else中,输出了123。但是没有走trycatch代码?不知道是什么原因?
使用Mocha测试异步代码并不简单!只需在测试完成后调用回调。通过添加一个回调(通常命名done)it(),Mocha将知道它应该等待调用此函数来完成测试。此回调接受Error实例(或其子类)或伪值; 其他任何事情都会导致测试失败。 describe('User', function() { describe('#save()', function() { it('should save wi
异步代码是指当调用后不会立即完成的代码。 setTimeout(() => { console.log('do stuff'); }, 3000 ) 在 setTimeout 执行完3秒后 do stuff 会输出到控制台。我们可以看出当指定的时间过去后我们所提供的异步函数会触发。现在来看个更有启发性的示例: doWork( () => { console.log('call me whe
问题内容: 我们正在与节点合作,主要用于内部项目,并了解使用该技术的最佳方法。 并非来自特定的异步背景,学习曲线可能是一个挑战,但是我们已经习惯了框架和学习过程。 使我们两极分化的是,何时才是使用同步代码与异步代码的最佳时间。我们目前使用的规则是,如果任何东西与IO进行交互,那么它必须通过回调或事件发射器(即给定的)是异步的,但是可以将任何未使用IO的其他项构造为同步函数(此方法还将取决于函数本身
这是我的代码: 如果我先调用readAllData(),然后再调用readData(),我会得到一个RangeError:
我可能还不够清楚--情况是,我的现有代码不支持异步,我希望使用新的库,如System.net.http和只支持异步方法的AWS SDK。因此,我需要弥补这一差距,并能够拥有可以同步调用的代码,然后可以在其他地方调用异步方法。 我读了很多书,有很多次有人问这个问题,也有人回答这个问题。 从非异步方法调用异步方法