Quellcode durchsuchen

完成 compileToFunctions 的作用

HcySunYang vor 7 Jahren
Ursprung
Commit
9ef2d0c5d9
1 geänderte Dateien mit 75 neuen und 0 gelöschten Zeilen
  1. 75 0
      note/7创建编译器.md

+ 75 - 0
note/7创建编译器.md

@@ -343,6 +343,81 @@ if (process.env.NODE_ENV !== 'production') {
 
 另外,这段代码也是运行在非生产环境的,且错误信息 `compiled.errors` 和提示信息 `compiled.tips` 都是数组,需要遍历打印,不同的是错误信息使用 `warn` 函数进行打印,而提示信息使用 `tip` 函数进行打印,其中 `tip` 函数也来自于 `core/util/debug.js` 文件。
 
+在往下是这样一段代码:
+
+```js
+// turn code into functions
+const res = {}
+const fnGenErrors = []
+res.render = createFunction(compiled.render, fnGenErrors)
+res.staticRenderFns = compiled.staticRenderFns.map(code => {
+  return createFunction(code, fnGenErrors)
+})
+```
+
+定义了两个常量 `res` 以及 `fnGenErrors`,其中 `res` 是一个空对象且它就是最终的返回值,`fnGenErrors` 是一个空数组。然后在 `res` 对象上添加一个 `render` 属性,这个 `render` 属性,实际上就是最终生成的渲染函数,它的值是通过 `createFunction` 创建出来了,其中 `createFunction` 函数就定义在 `to-function.js` 文件的开头,源码如下:
+
+```js
+function createFunction (code, errors) {
+  try {
+    return new Function(code)
+  } catch (err) {
+    errors.push({ err, code })
+    return noop
+  }
+}
+```
+
+`createFunction` 函数接收两个参数,第一个参数 `code` 为函数体字符串,该字符串将通过 `new Function(code)` 的方式创建为函数。第二个参数 `errors` 是一个数组,作用是当采用 `new Function(code)` 创建函数发生错误时用来收集错误的。我们再查看一下调用 `createFunction` 那句代码:
+
+```js
+res.render = createFunction(compiled.render, fnGenErrors)
+```
+
+可知,传递给 `createFunction` 函数的第一个参数是 `compiled.render`,所以 `compiled.render` 应该是一个函数体字符串,且我们知道 `compiled` 是 `compile` 函数的返回值,这说明:*`compile` 函数编译模板字符串后所得到的是字符串形式的函数体*。传递给 `createFunction` 函数的第二个参数是之前声明的 `fnGenErrors` 常量,也就是说当创建函数出错时的错误信息被 `push` 到这个数组里了。
+
+在这句代码之后,又在 `res` 对象上添加了 `staticRenderFns` 属性:
+
+```js
+res.staticRenderFns = compiled.staticRenderFns.map(code => {
+  return createFunction(code, fnGenErrors)
+})
+```
+
+由这段代码可知 `res.staticRenderFns` 是一个函数数组,是通过对 `compiled.staticRenderFns` 变量生成的,这说明:*`compiled` 除了包含 `render` 字符串外,还包含一个字符串数组 `staticRenderFns`,且这个字符串数组最终也通过 `createFunction` 转为函数。* `staticRenderFns` 的主要作用是渲染优化,我们后面详细讲解。
+
+再接下来就是 `compileToFunctions` 函数的最后一段代码:
+
+```js
+// check function generation errors.
+// this should only happen if there is a bug in the compiler itself.
+// mostly for codegen development use
+/* istanbul ignore if */
+if (process.env.NODE_ENV !== 'production') {
+  if ((!compiled.errors || !compiled.errors.length) && fnGenErrors.length) {
+    warn(
+      `Failed to generate render function:\n\n` +
+      fnGenErrors.map(({ err, code }) => `${err.toString()} in\n\n${code}\n`).join('\n'),
+      vm
+    )
+  }
+}
+```
+
+这段代码同样是在非生产环境下执行的,这段代码主要的作用是用来打印在生成渲染函数过程中的错误,也就是上面定义的常量 `fnGenErrors` 中所收集的错误。注释中写的很清楚,这段代码的作用主要是用于开发 `codegen` 功能时使用,一般是编译器本身的错误,所以对于我们来讲基本用不到。
+
+最后一句代码我们前面已经讲过:`return (cache[key] = res)` 返回结果的同时将结果缓存。
+
+现在我们回顾一下 `src/compiler/to-function.js` 文件的整个内容,可以发现这个文件的主要作用有以下几点:
+
+* 1、缓存编译结果,通过 `createCompileToFunctionFn` 函数内声明的 `cache` 常量实现。
+* 2、调用 `compile` 函数将模板字符串转成渲染函数字符串
+* 3、调用 `createFunction` 函数将渲染函数字符创转成真正的渲染函数
+* 4、打印编译错误,包括:模板字符串 -> 渲染函数字符 以及 渲染函数字符串 -> 渲染函数 这两个阶段的错误
+
+最后,真正的 `模板字符串` 到 `渲染函数字符串` 的编译工作实际上是通过调用 `compile` 函数来完成的,所以接下来我们的任务就是弄清楚 `compile` 函数。
+
+#### compile 的作用