温州免费建站模板免费网站优化软件

当前位置: 首页 > news >正文

温州免费建站模板,免费网站优化软件,公司网站做推广,徐州东站一.watch是懒加载 #x1f50d; 一、什么是「懒更新」和「立即更新」#xff1f; 类型 默认行为 含义 watch 懒执行 初始时不会执行#xff0c;只有依赖发生变化时才触发回调 watchEffect 立即执行 在一开始就会自动运行一次#xff0c;并收集依赖 注#xff1a;更改响应…一.watch是懒加载 一、什么是「懒更新」和「立即更新」 类型 默认行为 含义 watch 懒执行 初始时不会执行只有依赖发生变化时才触发回调 watchEffect 立即执行 在一开始就会自动运行一次并收集依赖 注更改响应式状态而且watch或者watcheffect 都是在组件更新前调用。 所以访问到的dom是更新前的状态。要访问更新后的状态 需要要用watchPostEffect而组件卸载两个 watch都是自动的停止。两个watch里面写了异步语句。还需要手动停止。 最好只写同步语句。不要在里面写异步语句 可能会内存泄露。 ✅ 二、watch 示例 import { ref, watch } from ‘vue’; const count ref(0); // 默认懒执行一开始不会触发 watch(count, (newVal, oldVal) { console.log(‘count changed from’, oldVal, ‘to’, newVal); }); // 立即执行加 immediate 选项 watch(count, (newVal, oldVal) { console.log(‘immediate: count is’, newVal); }, { immediate: true }); 二、watchEffcet的使用。可能存在的问题 ✅ 重点一 watchEffect 可以不用传 todoId它就知道监听谁的变化。 完全正确这正是 watchEffect 的最大优势之一 ✅ 自动依赖追踪 watchEffect(() { // Vue 会自动追踪 todoId.value 的访问 fetch(api?todoId\({todoId.value}); }); ✔️ 你不需要显式告诉它监听什么只要在 effect 函数中使用了某个响应式变量它就会追踪这个变量。 ✅ 第二个重点 注意点是只监听第一个 await 前面读取到的响应式值。 这也是绝对正确的而且是使用 watchEffect async 的 常见陷阱所以我才强调 onInvalidate。 ⚠️ 为什么我要强调 onInvalidate 虽然你可以不写 onInvalidate但如果你的副作用里有 await就有可能出现竞态条件race condition的问题 举个例子 watchEffect(() { // todoId 是响应式的 const id todoId.value; // 等待异步请求 const res await fetch(/api/todo/\){id}); data.value await res.json(); }); ⛔ 问题如果 todoId 快速变化两次 你可能会先收到第2次请求的结果然后第1次的结果又晚到了把数据“写回去了”。这会导致 UI 显示错误的数据。 ✅ 正确做法加 onInvalidate watchEffect((onInvalidate) { let canceled false; const id todoId.value; const fetchData async () { const res await fetch(/api/todo/\({id}); const json await res.json(); if (!canceled) { data.value json; } }; fetchData(); onInvalidate(() { canceled true; }); }); 这样可以防止异步“回写旧数据”。 ✅ 再说说你提到的性能问题 watchEffect 比 watch 性能高多属性监听更有效 这个说法部分成立具体情况要看场景 ✅ watchEffect 的性能优势 • 自动收集依赖只追踪你访问过的响应式属性 • 比起 watch([a, b, c]) 明确列出多个监听值watchEffect 自动感知并收敛依赖 • 非常适合监听多个响应式值组合、或者不确定依赖项的场景。 ✅ 总结你的重点 vs 我的补充 你提到的重点 我的补充说明 watchEffect 不用传依赖 ✔️ 依赖是自动追踪的 watchEffect 会监听第一个 await 之前访问的响应式值 ✔️ 这就是依赖收集点 watchEffect 更适合多依赖监听 ✔️ 自动追踪多个响应式依赖 为什么你讲 onInvalidate 为了避免 await 带来的异步副作用污染比如旧数据回写的问题是一种“竞态控制”手段 如果你想写 简洁版本不考虑竞态可以这样写 watchEffect(() { fetch(/api/todo/\){todoId.value}) .then(res res.json()) .then(json { data.value json; }); }); 三、详细说说竞争状态 为什么在 watchEffect 中处理异步时需要加 onInvalidate它是怎么避免竞态条件的 什么是「竞态条件」(race condition) 这是一个异步中的经典问题 多个异步请求先后发出但后发的请求先返回结果被先发的旧数据覆盖了。 举个真实例子来说明问题 场景 const todoId ref(1); const data ref(null); 你监听 todoId 的变化来请求数据 watchEffect(async () { const id todoId.value; const res await fetch(/api/todo/\({id}); const json await res.json(); data.value json; }); ❌ 出现问题的时机 用户快速点两下按钮让 todoId 从 1 → 2导致两次 fetch 同时进行 1. 请求 A /api/todo/1稍慢 2. 请求 B/api/todo/2稍快 结果请求 B 先回来显示 todo 2但随后 请求 A 回来了又把旧数据覆盖掉 ✅ 为什么 onInvalidate() 可以避免 onInvalidate 的作用是 在下一次 watchEffect 重新执行前Vue 会调用你上一次传入的清理函数。你可以在里面设置一个标志位或取消异步操作。 ✅ 改进版本关键代码 watchEffect((onInvalidate) { let canceled false; // 注册清理逻辑下一次执行前触发 onInvalidate(() { canceled true; }); const id todoId.value; const fetchData async () { const res await fetch(/api/todo/\){id}); const json await res.json(); // 如果这次已经作废就不要用结果了 if (!canceled) {data.value json; }}; fetchData(); }); 这段代码发生了什么 每次 todoId 变了 1. Vue 会重新执行 watchEffect 2. 在执行之前它会调用上一次的 onInvalidate 回调 3. 你就可以设置 canceled true 来标记上一次异步结果为「无效」 4. 如果老请求返回得慢代码会检查这个标志不再更新 data ✅ 为什么这就解决了竞态问题 因为只有最新一轮发出的请求的结果会被接收。老的 fetch 请求即使返回它的结果也会被忽略。 更专业的做法使用 AbortController 如果你用的是支持 fetch 取消的浏览器还可以配合 AbortController watchEffect((onInvalidate) { const controller new AbortController(); fetch(/api/todo/${todoId.value}, { signal: controller.signal }) .then(res res.json()) .then(json { data.value json; }) .catch(err { if (err.name ! ‘AbortError’) { console.error(‘fetch error:’, err); } }); onInvalidate(() { controller.abort(); // 真正取消上一个请求 }); }); ✅ 总结一句话 onInvalidate 就是 watchEffect 中的“清理钩子”你可以在里面取消或废弃上一次副作用保证只有最新的数据才会被应用从而完美避免异步请求中的竞态问题。