>웹 프론트엔드 >View.js >Vue의 반응성 원칙은 무엇입니까?

Vue의 반응성 원칙은 무엇입니까?

醉折花枝作酒筹
醉折花枝作酒筹앞으로
2021-07-29 17:42:193058검색

저는 최근 Vue 원리에 대한 많은 기사를 읽었습니다. 이 기사의 도움으로 Vue의 소스 코드를 직접 이해하려고 여러 번 노력했습니다. 드디어 다른 글과는 다른 관점으로 여러분께 Vue를 친숙하게 다가갈 수 있는 콘텐츠를 직접 출력해 볼 때가 된 것 같습니다.

Vue의 반응성 원칙은 무엇입니까?

Dep

var Dep = function Dep() {
  this.id = uid++
  this.subs = []
}

Dep의 의미는 당연히 의존성(즉, 의존성, 컴퓨터 분야의 명사)입니다.

node.js 프로그램을 작성하는 것과 마찬가지로 npm Warehouse의 종속성이 자주 사용됩니다. Vue에서 종속성은 구체적으로 반응적으로 처리된 데이터를 나타냅니다. 나중에 언급하겠지만 반응형 처리의 핵심 기능 중 하나는 DefineReactive이며 이는 많은 Vue 원칙 기사에서 언급됩니다.

Dep이 각 반응형 데이터에 바인딩된 후 반응형 데이터는 종속성(명사)이 됩니다. 아래 Watcher를 소개할 때 반응형 데이터가 템플릿에서 감시, 계산 또는 사용될 수 있음이 언급됩니다(동사).

subs

Dep 배열인 subs 속성이 있는데, 이는 구독자 목록을 의미한다고 추측하기 쉽습니다. 구독자는 감시 기능, 계산 기능 또는 보기 업데이트 기능일 수 있습니다.

Watcher

Watcher는 Dep에서 언급한 구독자입니다(나중에 Observer 관찰자와 혼동하지 마세요).

Watcher의 기능은 일부 앱의 구독 푸시와 마찬가지로 Dep 업데이트에 적시에 응답하는 것이기 때문입니다. 업데이트되었습니다.

deps

Dep에 subs 속성이 있는 것과 유사하게 Watcher 개체에도 deps 속성이 있습니다. 이는 Watcher와 Dep 사이의 다대다 관계를 구성합니다. 서로를 기록하는 이유는 한 당사자가 삭제되면 관련 개체가 시간에 업데이트될 수 있기 때문입니다.

Watcher 생성 방법

위에서 여러 번 언급한 watch, 계산 및 렌더링 템플릿은 Vue 소스 코드에서 간결하고 이해하기 쉬운 Watcher를 생성합니다.

  • mountComponent's vm._watcher = new Watcher(vm , updateComponent, noop);
  • initCompulated's watchers[key] = new Watcher(vm, getter || noop, noop, ComputedWatcherOptions)
  • $watcher의 var watcher = new Watcher(vm, expOrFn, cb, options);

Observer

Observer는 반응형 객체(또는 배열)를 재귀적으로 관찰(또는 처리)하는 역할을 담당하는 관찰자입니다. 인쇄된 예에서 반응 객체에는 관찰된 내용의 증거인 __ob__이 있음을 알 수 있습니다. 관찰자는 위의 Dep 및 Watcher만큼 중요하지 않으며 약간의 이해만으로도 충분합니다.

walk

Observer.prototype.walk는 Observer 초기화 시 재귀적 처리의 핵심 메소드인데, 이 메소드는 객체를 처리하는 데 사용되며, 배열을 처리하는 Observer.prototype.observeArray도 있습니다.

핵심 프로세스

위 개념 간의 관계에 따라 이를 일치시키는 방법과 반응형 데이터 업데이트를 달성하는 방법은 무엇입니까?

먼저 목표를 설정하세요. 데이터가 업데이트되면 자연스럽게 뷰가 자동으로 새로 고쳐져 최신 데이터가 표시됩니다.

위에서 언급한 Dep과 Watcher의 관계입니다. 데이터는 Dep이고 Watcher는 페이지 렌더링 기능을 트리거합니다(가장 중요한 Watcher입니다).

하지만 새로운 질문이 생깁니다. Dep은 감시자가 자신에게 의존한다는 것을 어떻게 알 수 있습니까?

Vue는 매우 흥미로운 방법을 채택합니다.

  • Watcher의 콜백 함수를 실행하기 전에 먼저 현재 Watcher가 무엇인지 기록합니다(Dep.target을 통해).

  • 콜백 함수 실행에 반응형 데이터가 사용됩니다. 반응형 데이터의 getter 함수는 필연적으로 호출됩니다

  • 반응형 데이터의 getter 함수에서는 현재 Watcher를 기록할 수 있으며, 이후 반응형 데이터가 업데이트되면 Dep과 Watcher 간의 관계가 구축됩니다. , 필연적으로 리액티브 데이터를 호출하는 setter 함수

  • 이전에 설정된 관계를 기반으로 Watcher에 해당하는 콜백 함수가 setter 함수에서 트리거될 수 있습니다

  • Code

  • 위의 논리는 다음과 같습니다. DefineReactive 함수. 이 기능에는 여러 가지 입구가 있습니다. 먼저 더 중요한 관찰 기능에 대해 이야기해 보겠습니다.

observer 함수에서는 새로운 Observer 객체가 생성되는데 Observer.prototype.walk를 사용하여 객체의 값을 하나씩 반응형으로 처리하고, DefineReactive 함수를 사용합니다.

defineReactive 함수는 워낙 중요하고 길지 않기 때문에 여기에 직접 올리는 것이 더 편리합니다.

function defineReactive(obj, key, val, customSetter, shallow) {
  var dep = new Dep()
  depsArray.push({ dep, obj, key })
  var property = Object.getOwnPropertyDescriptor(obj, key)
  if (property && property.configurable === false) {
    return
  }

  // cater for pre-defined getter/setters
  var getter = property && property.get
  var setter = property && property.set

  var childOb = !shallow && observe(val)
  Object.defineProperty(obj, key, {
    enumerable: true,
    configurable: true,
    get: function reactiveGetter() {
      var value = getter ? getter.call(obj) : val
      if (Dep.target) {
        dep.depend()
        if (childOb) {
          childOb.dep.depend()
          if (Array.isArray(value)) {
            dependArray(value)
          }
        }
      }
      return value
    },
    set: function reactiveSetter(newVal) {
      var value = getter ? getter.call(obj) : val
      // 后半部分诡异的条件是用于判断新旧值都是 NaN 的情况
      if (newVal === value || (newVal !== newVal && value !== value)) {
        return
      }
      // customSetter 用于提醒你设置的值可能存在问题
      if ('development' !== 'production' && customSetter) {
        customSetter()
      }
      if (setter) {
        setter.call(obj, newVal)
      } else {
        val = newVal
      }
      childOb = !shallow && observe(newVal)
      dep.notify()
    },
  })
}

우선, 각 반응형 값은 "종속성"이므로 첫 번째 단계에서는 클로저 기능을 사용하여 각 값에 대한 Dep를 생성합니다. (Vue 3에서는 클로저가 필요하지 않습니다.)

그런 다음 세 가지 핵심 매개변수를 살펴보세요.

obj 값이 현재 반응적으로 처리되어야 하는 개체

  • key 값의 키

  • val Current

  • 값에는 이전에 정의된 자체 getter 및 setter가 있을 수 있으므로 Vue의 반응형 처리를 수행할 때 원래 getter 및 setter를 먼저 처리해야 합니다.

  • 핵심 프로세스에서 위에서 언급한 것처럼 getter 함수는 특히 dep.dependent()에 의존하여 Dep과 Watcher 간의 관계를 설정합니다.

아래에는 Dep과 Watcher가 서로 전화를 걸 수 있는 몇 가지 방법이 게시되어 있습니다.

Dep.prototype.depend = function depend() {
  if (Dep.target) {
    Dep.target.addDep(this)
  }
}
Watcher.prototype.addDep = function addDep(dep) {
  var id = dep.id
  if (!this.newDepIds.has(id)) {
    this.newDepIds.add(id)
    this.newDeps.push(dep)
    if (!this.depIds.has(id)) {
      dep.addSub(this)
    }
  }
}
Dep.prototype.addSub = function addSub(sub) {
  this.subs.push(sub)
}

通过这几个函数,可以领略到了 Dep 和 Watcher 错综复杂的关系……不过看起来迂回,简单来说,其实做的就是上面说的互相添加到多对多列表。

你可以在 Dep 的 subs 找到所有订阅同一个 Dep 的 Watcher,也可以在 Watcher 的 deps 找到所有该 Watcher 订阅的所有 Dep。

但是里面还有一个隐藏问题,就是 Dep.target 怎么来呢?先放一放,后会作出解答。先接着看看 setter 函数,其中的关键是 dep.notify()。

Dep.prototype.notify = function notify() {
  // stabilize the subscriber list first
  var subs = this.subs.slice()
  for (var i = 0, l = subs.length; i < l; i++) {
    subs[i].update()
  }
}

不难理解,就是 Dep 提醒他的订阅者列表(subs)里的所有人更新,所谓订阅者都是 Watcher,subs[i].update() 调用的也就是 Watcher.prototype.update。

那么来看一下 Watcher 的 update 做了什么——

Watcher.prototype.update = function update() {
  if (this.lazy) {
    this.dirty = true
  } else if (this.sync) {
    this.run()
  } else {
    queueWatcher(this)
  }
}

在这里我觉得有两个点比较值得展开,所以挖点坑

위 내용은 Vue의 반응성 원칙은 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 segmentfault.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제