Open qiuhongbingo opened 3 years ago
/** * 0. * 假设我们有一个函数 getPicTotal * 传入两个用户名称后,分别查找用户的图片数量 * 最后将图片数量相加返回 * @param {*} name1 * @param {*} name2 */ function getPicTotal(name1, name2) { const num1 = getPicNum(name1) const num2 = getPicNum(name2) return num1 + num2 } getPicTotal() /** * 1. * 上面是同步的方法,如果 getPicNum 需要请求服务器来获取数据 * 那么我们需要改成异步调用 */ async function getPicTotal(name1, name2) { const [num1, num2] = await Promise.all([ getPicNum(name1), getPicNum(name2) ]) return num1 + num2 } await getPicTotal() /** * 2. * 但是,当一个函数变为 async 后,意味着调用它的函数也需要 await * 这破坏了 getPicTotal 的同步特性 * 有没有什么办法能让 getPicTotal 在保持现有调用方式不变的情况下实现异步请求呢? * 以下为伪代码实现 */ function getPicTotal(name1, name2) { const num1 = getPicNum(name1) const num2 = getPicNum(name2) return num1 + num2 } function getPicNum(name) { /** * 执行 perform name 时 * 函数调用栈会从 getPicNum 方法内跳出 * 被外层的 try handle 捕获 * 这有点类似 throw error 后被 try catch 捕获,但不同的是,这里的调用栈暂时不会被销毁 */ const num = perform name return num } try { getPicTotal('小明', '小华') } handle (who) { // try handle 是虚构的语法,但足以演示代数效应的思想 switch (who) { case '小明': // who === getPicNum perform 的 name 值 // 执行完 resume with 后,调用栈会回到 getPicNum,此时 num === 1 resume with 1 case '小华': resume with 2 default: resume with 0 } } /** * 总结:代数效应能够将副作用(例子中为请求图片数量)从函数逻辑中分离,使函数关注点保持纯粹 * 而代数效应在 react 中的应用便是 hooks,不需要区分 num 是异步还是同步 */ function App() { const [num, updateNum] = useState(0) return <button onClick={() => updateNum((num) => num + 1)}>{num}</button> }