详解Angular中的变更检测(十四)- 扩展知识1

94 阅读3分钟

开启掘金成长之旅!这是我参与「掘金日新计划 · 12 月更文挑战」的第12天,点击查看活动详情

前面,我们花了大量的篇幅去介绍Angular的变更检测机制,从最基础的原生JS的“变更检测”,到AngularNgZOne;从开发过程中两个常见的错误,到Angular的变更检测机制工作原理;从Default变更检测到OnPush变更检测;从各种示例代码,到如何减少变更检测次数来提升Angular应用的性能。

那我们肯定会好奇,其他优秀的前端框架是怎么实现“变更检测”的呢?

VUE/React中的“变更检测”

其他两大框架中的“变更检测”都有各自的特点。

VUE

实际上,在Vue中,我们称之为“数据响应式”,而且在Vue2中和Vue3中有不同的实现。

Vue2.0

Vue2.0 中的“数据响应式”会根据不同的数据类型来做不同处理,如果是对象则采用

Object.defineProperty()

的方式定义数据拦截。

我们在定义一个Vue组件的时候,需要设置组件的数据data,当这个数据发生变化时,Vue就知道要进行响应了。这和Angular是完全不同的思路,Angular“监听”的是异步事件的执行,而Vue则是对数据的变化进行监听。

回到Vue中,当数据被访问或发生变化时,Vue感知并做出响应。而defineProperty()有一些缺陷,它对数据这样的对象则无能为力。所以 如果是数组通过覆盖数组对象原型的7个变更方法(push,pop,shift,unshift,sort,reverse,splice),使这些方法可以额外的做更新通知,从而做出响应,这在之前的文章中也提到过,就是Zone的原理的那部分。

这种机制很好的解决了数据响应式的问题,但是实际使用中也存在一些缺点:

  • 比如对象层级很深,在初始化的时候递归遍历造成性能损耗;
  • 新增和删除属性时需要用户使用Vue.set,Vue.delete这样特殊的api才能生效;
  • 对于ES6中新产生的Map和Set这些数据结构不支持等问题(需要单独处理);

Vue3.0

为了解决这些问题,Vue3重写了这一部分的实现:利用ES6的Proxy代理要响应式的数据,它有很多好处,编程体验是一致的(Vue3.0中使用Composition API,但是也支持Vue2.0的语法),不需要使用特殊的API,初始化性能和内存消耗得到了大幅的改善(可以作为懒响应式)。另外由于响应式的实现代码抽取为独立的reactivity包,使得我们可以更灵活的使用它,第三方的扩展开发起来更加的灵活了。

在Vue中,当数据发生变化时,并不会马上执行更新(“变更检测”),它的更新策略是采用批量异步更新策略。也就是说,当数据发生变化时,会调度一个更新任务(更新函数),会会把更新函数放入异步队列中,紧接着数据再次发生变化,再调度一个更新任务,但异步队列发现已经有了,就不会入队了。

React

在React中,我们要改变数据,只能通过调用 this.setState(...) 函数来改变数据,自然就知道数据什么时候改变了。当this.setState()被调用的时候,React会重新调用render方法来重新渲染UI。

这个this.setState执行后,页面会马上更新吗? 这个this.setState比较神奇,有些情况下,它会马上就更新DOM,有些情况下,它并不会马上更新DOM。具体的情况,大家可以查阅相关资料文章哦。

本文,我们对比Angular,Vue,React三大前端框架中的“数据响应式”,现在是不是感觉自己的格局打开了呢。