core-util.md 5.7 KB

core/util 目录下的工具方法全解

debug.js 文件代码说明

该文件主要导出三个函数,如下:

export let warn = noop
export let tip = noop
export let formatComponentName: Function = (null: any) // work around flow check

其中 warntip 都被初始化为 noop 即空函数,而 formatComponentName 被初始化为 null 但它将来会是一个函数类型(Function)。

接下来是这样一段代码:

if (process.env.NODE_ENV !== 'production') {
  // ...
}

这些代码被包含在一个环境判断的语句块内,这说明,这些代码只有在非生产环境才会生效,而在这些代码中我们能看到如下语句:

if (process.env.NODE_ENV !== 'production') {
  // 其他代码...

  warn = (msg, vm) => {
    // ...
  }

  tip = (msg, vm) => {
    // ...
  }

  formatComponentName = (vm, includeFile) => {
    // ...
  }

  // 其他代码...
}

上面的代码是简化过的,可以发现,在非生产环境下分别对 warntip 以及 formatComponentName 进行了赋值,且值都为函数,接下来我们分别看一下这三个函数的作用。

warn
tip
formatComponentName

env.js 文件代码说明

error.js 文件代码说明

该文件导出一个函数:handleError

handleError

源码如下:

export function handleError (err: Error, vm: any, info: string) {
  if (config.errorHandler) {
    config.errorHandler.call(null, err, vm, info)
  } else {
    if (process.env.NODE_ENV !== 'production') {
      warn(`Error in ${info}: "${err.toString()}"`, vm)
    }
    /* istanbul ignore else */
    if (inBrowser && typeof console !== 'undefined') {
      console.error(err)
    } else {
      throw err
    }
  }
}
  • 描述:用于错误处理

  • 参数:

    • {Error} err catch 到的错误对象,我们可以看到 Vue 源码中是这样使用的:

      try {
      ...
      } catch (e) {
      handleError(e, vm, `${hook} hook`)
      }
      
    • {any} vm 这里应该传递 Vue 实例

    • {String} info Vue 特定的错误提示信息

  • 源码分析

首先检测是否定义 config.errorHandler,其中 config 为全局配置,来自于 core/config.js。如果发现 config.errorHandler 为真,就会执行这句:

config.errorHandler.call(null, err, vm, info)

所以你尽管通过 Vue.config 修改 errorHandler 的定义即可自定义错误处理错误的方式:

Vue.config.errorHandler = (err, vm, info) => {

}

如果 config.errorHandler 为假,那么程序将走 else 分支,可以理解为默认的错误处理方式,如果不是生产环境,首先提示一段文字信息:

if (process.env.NODE_ENV !== 'production') {
    warn(`Error in ${info}: "${err.toString()}"`, vm)
}

然后判断是否是浏览器环境,是的话使用 console.error 打印错误信息,否则直接 throw err

if (inBrowser && typeof console !== 'undefined') {
    console.error(err)
} else {
    throw err
}

lang.js 文件代码说明

emptyObject
  • 源码如下:

    export const emptyObject = Object.freeze({})
    

options.js 文件代码说明

perf.js 文件代码说明

这个文件导出两个变量,分别是 markmeasure

export let mark
export let measure

接着是下面这段代码:

if (process.env.NODE_ENV !== 'production') {
  const perf = inBrowser && window.performance
  /* istanbul ignore if */
  if (
    perf &&
    perf.mark &&
    perf.measure &&
    perf.clearMarks &&
    perf.clearMeasures
  ) {
    mark = tag => perf.mark(tag)
    measure = (name, startTag, endTag) => {
      perf.measure(name, startTag, endTag)
      perf.clearMarks(startTag)
      perf.clearMarks(endTag)
      perf.clearMeasures(name)
    }
  }
}

首先判断环境,如果不是生产环境,则继续,否则什么都不做。也就是说,如果是生产环境,那么这个文件导出的两个变量,都是 undefined

我们看一下,如果不是生产环境,又做了些什么,首先定义一个变量 perf

const perf = inBrowser && window.performance

如果在浏览器环境,那么 perf 的值就是 window.performance,否则为 false,然后做了一些列判断,目的是确定 performance 的接口可用,如果都可用,那么将初始化 markmeasure 变量。

首先看 mark

mark = tag => perf.mark(tag)

实际上,mark 是一个函数,这个函数的作用就是使用给定的 tag,通过 performance.mark() 方法打一个标记。

measure 方法接收三个参数,这三个参数与 performance.measure() 方法所要求的参数相同,它的作用就是调用一下 performance.measure() 方法,然后调用三个清除标记的方法:

perf.clearMarks(startTag)
perf.clearMarks(endTag)
perf.clearMeasures(name)

可以发现,其实 markmeasure 这两个函数就是对 performance.mark()performance.measure() 的封装。对于 performance.mark()performance.measure() 这两个方法的详情,大家可以查看 Performance,这里我将用一个通俗的说法尽快让大家明白 markmeasure 的作用,首先 mark 可以理解为“打标记”,比如如下代码我们在 for 循环的前后各打一个标记:

mark('for-start')
for (let i = 0; i < 100; i++) {
    console.log(i)
}
mark('for-end')

但是仅仅打标记是没有什么用的,这个时候就需要 measure 方法,它能够根据两个标记来计算这两个标记间代码的性能数据,你只需要这样即可:

measure('for-measure', 'for-start', 'for-end')

props.js 文件代码说明