响应式原理介绍

我们今天来讲讲,啥是响应式,以及Vue是怎么来做到的

广义的响应式

响应式是一种编程概念(英语:Reactive programming),是一种面向数据流和变化传播的编程范式。这意味着可以在编程语言中很方便地表达静态或动态的数据流,而相关的计算模型会自动将变化的值通过数据流进行传播

例如 a = b + c, 那么当b的数值发生变化时,a的值会随着b或c的值变化而自动变化

最简单的例子就是Excel的公式。单元格可以包含字面值或类似"=B1+C1"的公式,而包含公式的单元格的值会依据其他单元格的值的变化而变化

前端中的响应式

响应式响应式网页设计不同

响应式网页设计(英语:Responsive web design,通常缩写为RWD),或称自适应网页设计、回应式网页设计、对应式网页设计。 是一种网页设计的技术做法,该设计可使网站在不同的设备(从桌面计算机显示器到移动电话或其他移动产品设备)上浏览时对应不同分辨率皆有适合的呈现,减少用户进行缩放、平移和滚动等操作行为。我们更多情况下,会将其称为 页面多端适配

前端为什么需要响应式

经常学习东西的时候,不光要埋头前进,还要抬头看路,看看脚下这条路到底通到哪里

在前端展示页面当中,承载渲染输出的载体是HTML,这是一种类xml的超文本语言,内部的数据并不具有类似Excel的响应式刷新的功能,那么在页面越来越复杂的今天,展示静态页面已经远远不能满足我们的需求了

那么如果现在又一个证券交易平台的前端展示页面,要求头部数据随机显示一支涨幅在前十的股票,实时刷新,那么我们会怎么做?

通过querySelector从DOM中找到对应节点,动态的更新数据

没错,这个方法确实ok,那么假如旁边还有一栏需要显示涨幅最高的全部十只股票,并且价格也需要刷新呢,这时候我们刚刚的方法可能就不太奏效了

我们也可以用之前的方法。那么还有两栏也有这几只股票,也需要实时刷新呢?这时候再来一个一个替换,是不是会有点捉襟见肘了

那么假如这十只股票的价格都是响应式的,那么问题就解决了,我们只需要维护一个对象即可,后面所有的数据更新都是响应式的,不需要我们直接一个一个操作DOM了

That's why

Vue中的响应式

前端框架中,这也称为数据绑定,我们的数据和真实的DOM进行了绑定了,这也是个合适的比喻

为了实现上面的响应式,主要有下面几种方法:

  • 发布订阅模式(backbone.js)
  • 脏值检查(Angular.js)
  • 数据劫持 + 发布订阅(Vue.js)

发布订阅

这个模式十分经典了,就是传统的订阅模式

消息的发送者(称为发布者)不会将消息直接发送给特定的接收者(称为订阅者)。而是将发布的消息分为不同的类别,无需了解哪些订阅者(如果有的话)可能存在

脏值检查

原理为通过定时器进行轮询查询,但是只在特定事件触发后进行脏值检测

  • DOM事件,譬如用户输入文本,点击按钮等。( ng-click )
  • XHR响应事件 ( $http )
  • 浏览器Location变更事件 ( $location )
  • Timer事件( $timeout , $interval )
  • 执行 $digest() 或 $apply()

数据劫持

这就是今天的重点了

劫持,泛指强制占据船舶、汽车等交通工具的控制权,如劫机

ES5中的新api Object.defineProperty 可以劫持所定义数值的 setter 和 getter

let val = 1

Object.defineProperty(data, key, {
    set: function(newVal) {
        if (val === newVal) return;
        console.log('哈哈哈,监听到值变化了 ', val, ' --> ', newVal);
        // 我没有劫持set函数,仍有赋值功能
        val = newVal;
    }
    get: function() {
        // 我劫持了get函数,每次data[key]只能取到0
        return 0
    }
});

数据劫持的原理很简单,重点是怎么通过数据劫持实现响应式

当数据被DOM元素读取的时候,我们会触发get函数,那么这个时候我们需要将这个DOM记录一下,这个过程我们有个高大上的解释名词:依赖收集

当数据发生变化的时候,我们会出发set函数,那么,如果要实现数据响应式,set需要做一点工作,更新到上面收集的依赖DOM上,这里也有个高大上的解释名词:派发更新

Vue响应式实现

下面的图来自Vue官网

imgs

别看着花里胡哨的,其实不是很复杂。

这里我们先看data,这里的getter setter,就是我们上面介绍的内容

进入data部分的操作是 render ‘Touch’, 指的是在页面初次渲染的时候,我们会使用了这个数据,接下来,getter指向watcher,完成一次依赖收集

TIP

我们的依赖收集和派发更新是交给watcher来进行管理的,这个后续再说明哈

出data的部分,就是setter被触发后,告诉watcher,完成一次派发更新

灰常简单,重点是怎么用js实现,并且无侵入的融入到Vue这个框架内部,这部分在整个框架思路介绍完后,再细讲

参考文献