vue在2024.09.03发布了3.5正式版本,其中包含多方面的升级和优化
性能优化
响应式系统重构优化,在内存占用、性能方面均有收益
Memory Usage Improvements
Given a test case with 1000 refs + 2000 computeds (1000 chained pairs) + 1000 effects subscribing to the last computed, comparing the total memory used by these class instances:
- Before (3.4.19): 1426k
- After (this PR): 631k (-56%)
Performance Comparison
Reasonable gains across the board, most notably for single ref invoking multiple effects (+118%~185%) and reading multiple invalidated computeds (+176%~244%).
- 单个 ref 调用多个 effects:当一个 ref(Vue 中的响应式数据)被多次使用并触发多个副作用(effects)时,性能提升了118%到185%。这意味着在 Vue 的新优化下,相同的操作现在比以前快了将近两倍。
- 读取多个无效的计算属性:计算属性是基于响应式数据的缓存值。当这些计算属性由于依赖的数据改变而变得无效时,重新读取这些属性的性能提升了176%到244%。这表明在处理多次读取失效的计算属性时,性能有了非常明显的提升
响应式相关
defnieProps支持解构
- 之前defineProps不支持解构,相比之前,支持解构后,不失响应式特性
const { count } = defineProps(['count'])
watch onWatcherCleanup支持注册清理函数
- Watch api中,监听对象发生变化后,清理副作用不再使用的引用,避免内存泄漏
watch(id, async (newId, oldId) => {const { response, cancel } = doAsyncWork(newId)// `cancel` will be called if `id` changes, cancelling// the previous request if it hasn't completed yetonWatcherCleanup(cancel)data.value = await response
})
function doAsyncWork(id: string) {const source = new AbortController();const { signal } = source;const response = fetch(`/api/data?id=${id}`, { signal });return { response, cancel: () => source.abort() };
}
- 和onEffectCleanup的区别,不在watch中用,就不会被注册生效
<script setup>
watchEffect(async () => {data1.value = await queryAsyncData('api1', id.value)data2.value = await queryAsyncData('api2', id.value)
})// When getting called outside of the scope of Watch API,
// since there is no active effect scope,
// therefore the cleanup callback for cancel will not be registered
async function pull() {data3.value = await queryAsyncData('api3', id.value)
}
pull()
</script>
watch deep支持数字
// infinite depth
watch(src, () => {}, { deep: true })// explicit depth
watch(src, () => {}, { deep: 1 })
新增pause/resume方法 控制effect执行
- 主要是为了避免一些不必要的副作用执行以提升性能,比如keep-alive组件,暂停deactive非激活状态下的副作用执行,或者结合IntersectionObserver延迟执行副作用场景
const { stop, resume, pause } = watch(refs,callback)stop()resume()pause()
onEffectCleanup支持注册清理函数
- 利用副作用,清除监听、定时器等不再使用的引用,避免内存泄漏
export function queryAsyncData(api, id) {const { response, cancel } = doAsyncWork(api, id)// `cancel` will be called if this function get called in Watch API and the effect source changed// so that previous pending request will be cancelled// if not yet completedif (getCurrentEffect()) {onEffectCleanup(cancel)}return response
}
// in component setup or vapor render
watchEffect(() => {on(el1, eventName.value, handler)on(el2, eventName.value, handler)
})// in runtime-vapor pkg
function on(el, event, handler) {el.addEventListener(event, handler)if (getCurrentEffect()) {onEffectCleanup(() => {el.removeEventListener(event, handler)})}
}
add failSilently argument for onScopeDispose
- onScopeDispose 用于在组件销毁时自动清除定时器,避免内存泄漏
import { ref, onScopeDispose } from 'vue';export default {setup() {const timer = ref(null);function startTimer() {timer.value = setInterval(() => {console.log('Timer is running');}, 1000);}// 当作用域销毁时,清除定时器onScopeDispose(() => {clearInterval(timer.value);},true);startTimer();return {timer,};},
};
- 新增参数,支持静默告警
- 其实就是提供了屏蔽告警日志的参数
其他新特性
useId
- 主要是为了创建唯一的id用在dom属性上,每次调用 useId()都会创建唯一的id
<script setup>
import { useId } from 'vue'const id = useId()
</script><template><form><label :for="id">Name:</label><input :id="id" type="text" /></form>
</template>
useTemplateRef
- 以往用ref既是用于响应式数据的,又用在dom上,就会会造成疑惑,所以专门有这个处理dom
<script setup>
import { useTemplateRef, onMounted } from 'vue'const inputRef = useTemplateRef('input')onMounted(() => {inputRef.value.focus()
})
</script><template><input ref="input" />
</template>
app.onUnmount()
- 卸载时一些处理,比如清理不必要的引用等
function install(app: App) {function cleanupSomeSideeffect() {/* ...*/}//清理app.onUnmount(cleanupSomeSideffect);
}app.config.throwUnhandledErrorInProduction
- 主要为了生产环境下抛出错误
app.config.throwUnhandledErrorInProduction = true
自定义元素
- Vue对Web Components的支持,使得开发者可以创建自定义元素,这些元素可以跨框架使用,甚至在不使用Vue.js的项目中也可以使用。
- 略