Ver código fonte

chore: modify typos

miaoyuxinbaby 7 anos atrás
pai
commit
6ab877e186
1 arquivos alterados com 19 adições e 19 exclusões
  1. 19 19
      docs/art/8vue-reactive-dep-watch.md

+ 19 - 19
docs/art/8vue-reactive-dep-watch.md

@@ -1,8 +1,8 @@
 # 渲染函数的观察者与进阶的数据响应系统
 
-实际上在 [揭开数据响应系统的面纱](/art/7vue-reactive.html) 一节中我们仅仅学习了数据响应系统的部分内容,比如当时我们做了一个合理的假设,即:`dep.depend()` 这句代码的执行就代表观察者被收集了,而 `dep.notify()` 的执行则代表触发了响应,但是我们并没有详细讲解 `dep` 本身是什么东西,我们只是把它当做了一个收集依赖的“筐”。除此之外我们也没有讲解数据响应系统中另一个很重要的部分,即 `Watcher` ,我们知道正是由于 `Watcher` 对所观察字段的求值才触发了字段的 `get`,从而才有了收集到该观察者的机会。本节我们的目标就是深入 `Vue` 中有关于这部分的具体源码,看一看这里面的秘密。
+实际上在 [揭开数据响应系统的面纱](./art/7vue-reactive.md) 一节中我们仅仅学习了数据响应系统的部分内容,比如当时我们做了一个合理的假设,即:`dep.depend()` 这句代码的执行就代表观察者被收集了,而 `dep.notify()` 的执行则代表触发了响应,但是我们并没有详细讲解 `dep` 本身是什么东西,我们只是把它当做了一个收集依赖的“筐”。除此之外我们也没有讲解数据响应系统中另一个很重要的部分,即 `Watcher` ,我们知道正是由于 `Watcher` 对所观察字段的求值才触发了字段的 `get`,从而才有了收集到该观察者的机会。本节我们的目标就是深入 `Vue` 中有关于这部分的具体源码,看一看这里面的秘密。
 
-为了更好讲解 `Dep` 和 `Watcher`,我们需要选择一个合适的切入点,这个切入点就是 `Vue.prototype._init` 函数。为什么是 `Vue.prototype._init` 呢?因为数据响应系统本身的切入点就是 `initState` 函数,而 `initState` 函数的调用就在 `_init` 函数中。现在我们把视线重新转移到 `_init` 函数,然后**试图从 `渲染(render)` -> `重新渲染(re-render)` 的过程探索数据响应系统更深层次的内容**。
+为了更好讲解 `Dep` 和 `Watcher`,我们需要选择一个合适的切入点,这个切入点就是 `Vue.prototype._init` 函数。为什么是 `Vue.prototype._init` 呢?因为数据响应系统本身的切入点就是 `initState` 函数,而 `initState` 函数的调用就在 `_init` 函数中。现在我们把视线重新转移到 `_init` 函数,然后 **试图从 `渲染(render)` -> `重新渲染(re-render)` 的过程探索数据响应系统更深层次的内容**。
 
 ## $mount 挂载函数
 
@@ -33,7 +33,7 @@ Vue.prototype._init = function (options?: Object) {
 
 以上是简化后的代码,注意高亮的那一句:`vm.$mount(vm.$options.el)`,这句代码是 `_init` 函数的最后一句代码,在这句代码执行之前完成了所有初始化的工作,虽然我们目前对初始化工作还有很多不了解的地方,不过没关系,现在我们就假设已经完成了所有初始化的工作,然后开始我们的探索,不过在这之前我们需要先了解一下 `$mount` 函数是如何将组件挂载到给定元素的。
 
-大家还记得 `$mount` 函数定义在哪里吗?我们在 [Vue 构造函数](/art/2vue-constructor.html) 一节中,在整理 `Vue` 构造函数的时候发现 `$mount` 的定义出现在两个地方,第一个地方是 `platforms/web/runtime/index.js` 文件,如下:
+大家还记得 `$mount` 函数定义在哪里吗?我们在 [Vue 构造函数](./art/2vue-constructor.md) 一节中,在整理 `Vue` 构造函数的时候发现 `$mount` 的定义出现在两个地方,第一个地方是 `platforms/web/runtime/index.js` 文件,如下:
 
 ```js
 Vue.prototype.$mount = function (
@@ -51,7 +51,7 @@ Vue.prototype.$mount = function (
 el = el && inBrowser ? query(el) : undefined
 ```
 
-首先检测是否传递了 `el` 选项,如果传递了 `el` 选项则会接着判断 `inBrowser` 是否为真,即当前宿主环境是否是浏览器,如果在浏览器中则将 `el` 透传给 `query` 函数并用返回值重写 `el` 变量,否则 `el` 将被重写为 `undefined`。其中 [query](/appendix/web-util.html#query) 函数来自 `src/platforms/web/util/index.js` 文件,用来根据给定的参数在 `DOM` 中查找对应的元素并返回。总之如果在浏览器环境下,那么 `el` 变量将存储着 `DOM` 元素(理想情况下)。
+首先检测是否传递了 `el` 选项,如果传递了 `el` 选项则会接着判断 `inBrowser` 是否为真,即当前宿主环境是否是浏览器,如果在浏览器中则将 `el` 透传给 `query` 函数并用返回值重写 `el` 变量,否则 `el` 将被重写为 `undefined`。其中 [query](../appendix/web-util.md#query) 函数来自 `src/platforms/web/util/index.js` 文件,用来根据给定的参数在 `DOM` 中查找对应的元素并返回。总之如果在浏览器环境下,那么 `el` 变量将存储着 `DOM` 元素(理想情况下)。
 
 接着来到 `$mount` 函数的第二句代码:
 
@@ -88,7 +88,7 @@ if (el === document.body || el === document.documentElement) {
 }
 ```
 
-首先如果传递了 `el` 参数,那么就使用 `query` 函数获取到指定的 `DOM` 元素并重新赋值给 `el` 变量,这个元素我们称之为挂载点。接着是一段 `if` 语句块,检测了挂载点是不是 `<body>` 元素或者 `<html>` 元素,如果是的话那么在非生产环境下会打印警告信息,警告你不要挂载到 `<body>` 元素或者 `<html>` 元素。为什么不允许这么做呢?那是因为挂载点的本意是**组件挂载的占位**,它将会被组件自身的模板**替换**掉,而  `<body>` 元素和 `<html>` 元素显然是不能被替换掉的。
+首先如果传递了 `el` 参数,那么就使用 `query` 函数获取到指定的 `DOM` 元素并重新赋值给 `el` 变量,这个元素我们称之为挂载点。接着是一段 `if` 语句块,检测了挂载点是不是 `<body>` 元素或者 `<html>` 元素,如果是的话那么在非生产环境下会打印警告信息,警告你不要挂载到 `<body>` 元素或者 `<html>` 元素。为什么不允许这么做呢?那是因为挂载点的本意是 **组件挂载的占位**,它将会被组件自身的模板 **替换**掉,而  `<body>` 元素和 `<html>` 元素显然是不能被替换掉的。
 
 继续看代码,如下是对 `$mount` 函数剩余代码的简化:
 
@@ -154,7 +154,7 @@ const idToTemplate = cached(id => {
 })
 ```
 
-如上代码所示 `idToTemplate` 是通过 `cached` 函数创建的。可以在附录 [shared/util.js 文件工具方法全解](/appendix/shared-util.html#cached) 中查看关于 `cached` 函数的讲解,该函数的作用是通过缓存来避免重复求值,提升性能。但 `cached` 函数并不改变原函数的行为,很显然原函数的功能是返回指定元素的 `innerHTML` 字符串。
+如上代码所示 `idToTemplate` 是通过 `cached` 函数创建的。可以在附录 [shared/util.js 文件工具方法全解](../appendix/shared-util.md#cached) 中查看关于 `cached` 函数的讲解,该函数的作用是通过缓存来避免重复求值,提升性能。但 `cached` 函数并不改变原函数的行为,很显然原函数的功能是返回指定元素的 `innerHTML` 字符串。
 
 `getOuterHTML` 函数的源码如下:
 
@@ -198,7 +198,7 @@ if (template) {
 }
 ```
 
-在处理完 `options.template` 选项之后,`template` 变量中存储着最终用来生成渲染函数的字符串,但正如前面提到过的 `template` 变量可能是一个空字符串,所以在上面代码中第一句高亮的代码对 `template` 进行判断,只有在 `template` 存在的情况下才会执行 `if` 语句块内的代码,而 `if` 语句块内的代码的作用就是使用 `compileToFunctions` 函数将模板(`template`)字符串编译为渲染函数(`render`),并将渲染函数添加到 `vm.$options` 选项中(`options` 是 `vm.$options` 的引用)。对于 `compileToFunctions` 函数我们会在讲解 `Vue` 编译器的时候详细说明,现在大家只需要知道他的作用即可,实际上在 `src/platforms/web/entry-runtime-with-compiler.js` 文件的底部我们可以看到这样一句代码:
+在处理完 `options.template` 选项之后,`template` 变量中存储着最终用来生成渲染函数的字符串,但正如前面提到过的 `template` 变量可能是一个空字符串,所以在上面代码中第一句高亮的代码对 `template` 进行判断,只有在 `template` 存在的情况下才会执行 `if` 语句块内的代码,而 `if` 语句块内的代码的作用就是使用 `compileToFunctions` 函数将模板(`template`)字符串编译为渲染函数(`render`),并将渲染函数添加到 `vm.$options` 选项中(`options` 是 `vm.$options` 的引用)。对于 `compileToFunctions` 函数我们会在讲解 `Vue` 编译器的时候详细说明,现在大家只需要知道他的作用即可,实际上在 `src/platforms/web/entry-runtime-with-compiler.js` 文件的底部我们可以看到这样一句代码:
 
 ```js
 Vue.compile = compileToFunctions
@@ -232,7 +232,7 @@ if (template) {
 }
 ```
 
-这两段高亮的代码是用来统计编译器性能的,我们在 `Vue.prototype._init` 函数中已经遇到过类似的代码,详细内容可以在 [以一个例子为线索](/art/3vue-example.html) 以及 [perf.js 文件代码说明](/appendix/core-util.html#perf-js-文件代码说明) 这两个章节中查看。
+这两段高亮的代码是用来统计编译器性能的,我们在 `Vue.prototype._init` 函数中已经遇到过类似的代码,详细内容可以在 [以一个例子为线索](./art/3vue-example.md) 以及 [perf.js 文件代码说明](../appendix/core-util.md#perf-js-文件代码说明) 这两个章节中查看。
 
 最后我们来做一下总结,实际上完整版 `Vue` 的 `$mount` 函数要做的核心事情就是编译模板(`template`)字符串为渲染函数,并将渲染函数赋值给 `vm.$options.render` 选项,这个选项将会在真正挂载组件的 `mountComponent` 函数中。
 
@@ -353,7 +353,7 @@ if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
 }
 ```
 
-这段代码的作用只有一个,即定义并初始化 `updateComponent` 函数,这个函数将用作创建 `Watcher` 实例时传递给 `Watcher` 构造函数的第二个参数,这也将使我们第一次真正的接触 `Watcher` 构造函数,不过现在我们需要先把 `updateComponent` 函数搞清楚,在上面的代码中首先定义了 `updateComponent` 变量,虽然是一个 `if...else` 语句块,其中 `if` 语句块的条件我们已经遇到过很多次了,在满足该添加的情况下会做一些性能统计,可以看到在 `if` 语句块中分别统计了 `vm._render()` 函数以及 `vm._update()` 函数的运行性能。也就是说无论是执行 `if` 语句块还是执行 `else` 语句块,最终 `updateComponent` 函数的功能是不变的。
+这段代码的作用只有一个,即定义并初始化 `updateComponent` 函数,这个函数将用作创建 `Watcher` 实例时传递给 `Watcher` 构造函数的第二个参数,这也将是我们第一次真正地接触 `Watcher` 构造函数,不过现在我们需要先把 `updateComponent` 函数搞清楚,在上面的代码中首先定义了 `updateComponent` 变量,虽然是一个 `if...else` 语句块,其中 `if` 语句块的条件我们已经遇到过很多次了,在满足该条件的情况下会做一些性能统计,可以看到在 `if` 语句块中分别统计了 `vm._render()` 函数以及 `vm._update()` 函数的运行性能。也就是说无论是执行 `if` 语句块还是执行 `else` 语句块,最终 `updateComponent` 函数的功能是不变的。
 
 既然功能相同,我们就直接看 `else` 语句块的代码,因为它要简洁的多:
 
@@ -368,12 +368,12 @@ if (process.env.NODE_ENV !== 'production' && config.performance && mark) {
 }
 ```
 
-可以看到 `updateComponent` 是一个函数,该函数的作用是以 `vm._render()` 函数的返回值作为第一个参数调用 `vm._update()` 函数。由于我们还没有讲解 `vm._render` 函数和 `vm._update` 函数的作用,所以为了让大家更好理解,我们可以简单认为:
+可以看到 `updateComponent` 是一个函数,该函数的作用是以 `vm._render()` 函数的返回值作为第一个参数调用 `vm._update()` 函数。由于我们还没有讲解 `vm._render` 函数和 `vm._update` 函数的作用,所以为了让大家更好理解,我们可以简单认为:
 
 * `vm._render` 函数的作用是调用 `vm.$options.render` 函数并返回生成的虚拟节点(`vnode`)
 * `vm._update` 函数的作用是把 `vm._render` 函数生成的虚拟节点渲染成真正的 `DOM`
 
-也就是说目前我们可以简单认为 `updateComponent` 函数的作用就是:**把渲染函数生成的虚拟DOM渲染成真正的DOM**,其实在 `vm._update` 内部是通过虚拟DOM的补丁算法(`patch`)来完成的,这些我们放到后面的具体章节去讲。
+也就是说目前我们可以简单认为 `updateComponent` 函数的作用就是:**把渲染函数生成的虚拟DOM渲染成真正的DOM**,其实在 `vm._update` 内部是通过虚拟DOM的补丁算法(`patch`)来完成的,这些我们放到后面的具体章节去讲。
 
 再往下,我们将遇到创建观察者(`Watcher`)实例的代码:
 
@@ -387,9 +387,9 @@ new Watcher(vm, updateComponent, noop, {
 }, true /* isRenderWatcher */)
 ```
 
-前面说过,这将是我们第一次真正意义上的遇到观察者构造函数 `Watcher`,我们在 [揭开数据响应系统的面纱](/art/7vue-reactive.html) 一章中有提到过,正是因为 `watcher` 对表达式的求值,触发了数据属性的 `get` 拦截器函数,从而收集到了依赖,当数据变化时能够触发响应。在上面的代码中 `Watcher` 观察者实例将对 `updateComponent` 函数求值,我们知道 `updateComponent` 函数的执行会间接触发渲染函数(`vm.$options.render`)的执行,而渲染函数的执行则会触发数据属性的 `get` 拦截器函数,从而将依赖(`观察者`)收集,当数据变化时将重新执行 `updateComponent` 函数,这就完成了重新渲染。同时我们把上面代码中实例化的观察者对象称为**渲染函数的观察者**。
+前面说过,这将是我们第一次真正意义上的遇到观察者构造函数 `Watcher`,我们在 [揭开数据响应系统的面纱](./art/7vue-reactive.md) 一章中有提到过,正是因为 `watcher` 对表达式的求值,触发了数据属性的 `get` 拦截器函数,从而收集到了依赖,当数据变化时能够触发响应。在上面的代码中 `Watcher` 观察者实例将对 `updateComponent` 函数求值,我们知道 `updateComponent` 函数的执行会间接触发渲染函数(`vm.$options.render`)的执行,而渲染函数的执行则会触发数据属性的 `get` 拦截器函数,从而将依赖(`观察者`)收集,当数据变化时将重新执行 `updateComponent` 函数,这就完成了重新渲染。同时我们把上面代码中实例化的观察者对象称为 **渲染函数的观察者**。
 
-## 初识 Watcher 
+## 初识 Watcher
 
 接下来我们就以渲染函数的观察者对象为例,顺着脉络了解 `Watcher` 类,`Watcher` 类定义在 `src/core/observer/watcher.js` 文件中,如下是 `Watcher` 类的全部内容:
 
@@ -403,7 +403,7 @@ export default class Watcher {
     options?: ?Object,
     isRenderWatcher?: boolean
   ) {
-    
+
   }
 
   get () {
@@ -458,7 +458,7 @@ new Watcher(vm, updateComponent, noop, {
 }, true /* isRenderWatcher */)
 ```
 
-可以看到在创建渲染函数观察者实例对象时传递了全部五个参数,第一个参数 `vm` 很显然就是当前组件实例对象;第二个参数 `updateComponent` 就是被观察的目标,它是一个函数;第三个参数 `noop` 是一个空函数;第四个参数是一个包含 `before` 函数的对象,这个对象将作为传递给该观察者的选项;第五个参数为 `true`,我们知道这个参数标识着该观察者实例对象是否是渲染函数的观察者,很显然上面的代码是在为渲染函数创建观察者对象,所以第五个参数自然为 `true`。
+可以看到在创建渲染函数观察者实例对象时传递了全部五个参数,第一个参数 `vm` 很显然就是当前组件实例对象;第二个参数 `updateComponent` 就是被观察的目标,它是一个函数;第三个参数 `noop` 是一个空函数;第四个参数是一个包含 `before` 函数的对象,这个对象将作为传递给该观察者的选项;第五个参数为 `true`,我们知道这个参数标识着该观察者实例对象是否是渲染函数的观察者,很显然上面的代码是在为渲染函数创建观察者对象,所以第五个参数自然为 `true`。
 
 这里有几个问题需要注意,首先被观察的表达式是一个函数,即 `updateComponent` 函数,我们知道 `Watcher` 的原理是通过对“被观测目标”的求值,触发数据属性的 `get` 拦截器函数从而收集依赖,至于“被观测目标”到底是表达式还是函数或者是其他形式的内容都不重要,重要的是“被观测目标”能否触发数据属性的 `get` 拦截器函数,很显然函数是具备这个能力的。另外一个我们需要注意的是传递给 `Watcher` 构造函数的第三个参数 `noop` 是一个空函数,它什么事情都不会做,有的同学可能会有疑问:“不是说好了当数据变化时重新渲染吗,现在怎么什么都不做了?”,实际上数据的变化不仅仅会执行回调,还会重新对“被观察目标”求值,也就是说 `updateComponent` 也会被调用,所以不需要通过执行回调去重新渲染。说到这里大家或许又产生了一个疑问:“再次执行 `updateComponent` 函数难道不会导致再次触发数据属性的 `get` 拦截器函数导致重复收集依赖吗?”,这是个好问题,不过不用担心,因为 `Vue` 已经实现了避免收集重复依赖的处理,我们后面会讲到的。
 
@@ -494,7 +494,7 @@ if (options) {
 
 我们平时在使用 `Vue` 的 `watch` 选项或者 `vm.$watch` 函数去观测某个数据时,可以通过设置 `deep` 选项的值为 `true` 来深度观测该数据。
 
-* `options.user`,用来标识当前观察者实例对象是**开发者定义的**还是**内部定义的**
+* `options.user`,用来标识当前观察者实例对象是 **开发者定义的** 还是 **内部定义的**
 
 实际上无论是 `Vue` 的 `watch` 选项还是 `vm.$watch` 函数,他们的实现都是通过实例化 `Watcher` 类完成的,等到我们讲解 `Vue` 的 `watch` 选项和 `vm.$watch` 的具体实现时大家会看到,除了内部定义的观察者(如:渲染函数的观察者、计算属性的观察者等)之外,所有观察者都被认为是开发者定义的,这时 `options.user` 会自动被设置为 `true`。
 
@@ -506,9 +506,9 @@ if (options) {
 
 默认情况下当数据变化时不会同步求值并执行回调,而是将需要重新求值并执行回调的观察者放到一个异步队列中,当所有数据的变化结束之后统一求值并执行回调,这么做的好处有很多,我们后面会详细讲解。
 
-* `options.before`,可以理解为 `Watcher` 实例的钩子,当数据变化之后,触发更新之前,调用
+* `options.before`,可以理解为 `Watcher` 实例的钩子,当数据变化之后,触发更新之前,调用在创建渲染函数的观察者实例对象时传递的 `before` 选项。
 
-在创建渲染函数的观察者实例对象时传递的 `before` 选项,如下高亮代码:
+如下高亮代码:
 
 ```js {2-6}
 new Watcher(vm, updateComponent, noop, {
@@ -592,7 +592,7 @@ export function parsePath (path: string): any {
 }
 ```
 
-首先我们需要知道 `parsePath` 函数接收的参数是什么,如下是平时我们使用 `$watch` 函数的例子:
+首先我们需要知道 `parsePath` 函数接收的参数是什么,如下是平时我们使用 `$watch` 函数的例子:
 
 ```js
 // 函数