ES 编码实践 —— 惰性载入函数

published

惰性载入函数能够避免执行不必要的代码。

假设,现在到了一个新的时代,人人都开始用 ES 削铅笔,由于这个需求很旺盛,各大引擎都准备添加这个功能。但是还没有统一的标准,所以各大引擎的实现也千差万别。这就苦了程序员,为了编写出通用的削铅笔代码,必须对各个引擎的功能支持情况进行判断。 假设,现在有两个引擎,对削铅笔的功能提供了支持:

  • eco 引擎,支持削铅笔功能的对象的构造函数是 ecoSP
  • mca 引擎,支持削铅笔功能的对象的构造函数是 mcaSP

现在来编写代码:

function createSP() {
  if (typeof ecoSP !== 'undefined') {
    return new ecoSP()
  } else if (typeof mcaSP !== 'undefined') {
    return new mcaSP()
  } else {
    throw new Error('No SP object available.')
  }
}

上面的代码,每次调用 createSP() 的时候,它都要对引擎进行检测 —— 先检测是不是 eco 引擎,再检测是不是 mca 引擎,如果都不是就抛出一个错误。这看起来没啥问题,但是代码在某一个引擎下执行,肯定都只会执行 if 语句的某一个分支。试想,如果代码运行在 eco 引擎下,每次都进行这种判断,不是挺蠢的嘛。如果 if 语句不必每次执行就好了,代码可以运行得更快点。解决的方案就是 惰性载入函数。 惰性载入表示函数执行的分支仅会发生一次。有两种实现惰性载入的方法:

  1. 在第一次调用时,根据情况覆写函数
  2. 在声明函数时,就指定适当的函数(与 1 相比,在第一次调用函数时不会损失性能,但是在代码首次加载时会损失性能)
function createSP() {
  if (typeof ecoSP !== 'undefined') {
    createSP = function () {
      return new ecoSP()
    }
  } else if (typeof mcaSP !== 'undefined') {
    createSP = function () {
      return new mcaSP()
    }
  } else {
    createSP = function () {
      throw new Error('No SP object available.')
    }
  }

  return createSP()
}

在这个惰性载入的 createSP() 中,if 语句的每一个分支都会为 createSP 变量赋值,这样会覆盖原有的函数定义,最后再调用新的函数。等到下一次再调用 createSP() 的时候,就会直接调用新的函数,这样就不用再次执行 if 语句了。

var createSP = (function () {
  if (typeof ecoSP !== 'undefined') {
    return function () {
      return new ecoSP()
    }
  } else if (typeof mcaSP !== 'undefined') {
    return function () {
      return new mcaSP()
    }
  } else {
    return function () {
      throw new Error('No SP object available.');
    }
  }
})()

这里创建了一个 IIFE。每个分支都返回合适的函数定义,以便立即执行后赋值给 createSP