Код-ревью, оптимизация внешнего кода

внешний интерфейс JavaScript
Код-ревью, оптимизация внешнего кода

Так называемое отсутствие правил и отсутствие кругов, время переднего плана в ходе групповой проверки кода показало, что код, написанный разными разработчиками в разные периоды, можно охарактеризовать как различающийся. Поэтому мы выдвинули некоторые соответствующие спецификации кода, надеясь в будущем сформировать стандарты кодирования команды.

В этой статье в основном оптимизируется некоторый JavaScript, чтобы сделать его более надежным, читабельным и удобным в сопровождении.

адрес гитхаба:GitHub.com/Майкл-Ли Чжиган…

Предыдущий:спецификация кода внешнего интерфейса code-review

Оптимизация решения if

Условные операторы JavaScript неизбежно используются в нашей повседневной разработке, но часто наш код написан не очень хорошо, серияif-elseИли несколько вложенных суждений сделают код очень раздутым.Следующие примеры оптимизированы.

Спрос: в настоящее время существует 4 продукта, а именно мобильные телефоны, компьютеры, телевизоры и игровые приставки.Конечно, цены на каждый продукт разные.

1. Самый простой способ: если судить

let commodity = {
  phone: '手机',
  computer: '电脑',
  television: '电视',
  gameBoy: '游戏机',
}

function price(name) {
  if (name === commodity.phone) {
    console.log(1999)
  } else if (name === commodity.computer) {
    console.log(9999)
  } else if (name === commodity.television) {
    console.log(2999)
  } else if (name === commodity.gameBoy) {
    console.log(3999)
  }
}
price('手机') // 9999

Недостатки: код слишком длинный, обслуживание и чтение неудобны.

2. Лучший способ:Switch

let commodity = {
  phone: '手机',
  computer: '电脑',
  television: '电视',
  gameBoy: '游戏机',
}
const price = (name) => {
  switch (name) {
    case commodity.phone:
      console.log(1999)
      break
    case commodity.computer:
      console.log(9999)
      break
    case commodity.television:
      console.log(2999)
      break
    case commodity.gameBoy:
      console.log(3999)
      break
  }
}
price('手机') // 9999

3. Лучший подход: шаблон стратегии

В шаблоне стратегии используются методы и идеи, такие как композиция, делегирование и полиморфизм, которые позволяют эффективно избежать множественных операторов условного выбора. Он обеспечивает идеальную поддержку принципа открытого-закрытого, инкапсулируя алгоритмы в отдельные стратегии, что упрощает их переключение, понимание и расширение.

const commodity = new Map([
  ['phone', 1999],
  ['computer', 9999],
  ['television', 2999],
  ['gameBoy', 3999],
])

const price = (name) => {
  return commodity.get(name)
}
price('phone') // 1999

Оптимизация включений

includes— это новый API в ES7, такой же, какindexOfразница в томincludesвозвращается напрямуюBooleanстоимость,indexOfЗатем возвращаемое значение индекса, как массив, так и строка, имеютincludesметод.

Требование: давайте реализуем метод аутентификации личности и возвращаем соответствующий результат проверки, передавая идентификатор личности.

традиционный метод

function verifyIdentity(identityId) {
  if (identityId == 1 || identityId == 2 || identityId == 3 || identityId == 4) {
    return '你的身份合法,请通行!'
  } else {
    return '你的身份不合法'
  }
}

includesоптимизация

function verifyIdentity(identityId) {
  if ([1, 2, 3, 4].includes(identityId)) {
    return '你的身份合法,请通行!'
  } else {
    return '你的身份不合法'
  }
}

для цикла

В JavaScript мы можем использоватьfor(),while(),for(in),for(of)Несколько видов петель, собственно, среди этих трех петельfor(in)крайне неэффективен, потому что ему нужно запрашивать хэш-ключ, поэтому его следует использовать как можно реже.

Наиболее традиционным оператором является цикл for, который работает с массивом с переменной i в качестве индекса, чтобы отслеживать, где к нему обращались.

var arr = ['a', 'b', 'c']
for (var i = 0; i < arr.length; i++) {
  console.log(arr[i]) //结果依次a,b,c
}

У вышеуказанного метода есть проблема: когда длина массива достигает миллионов,arr.lengthЭто должно быть вычислено миллион раз, что довольно интенсивно. Поэтому для его улучшения можно использовать следующие методы.

var arr = ['a', 'b', 'c']
for (var i = 0, length = arr.length; i < length; i++) {
  console.log(arr[i]) //结果依次a,b,c
}

В настоящее времяarr.lengthЕго нужно рассчитать только один раз, оптимизируя производительность.

for-inОбычно используется для обхода свойств объектов, но свойства необходимоenumerable(перечислимое) для чтения. в то же времяfor-inВы также можете пройти массив. При пересечении массива он проходит подпрыренное значение массива.

var obj = { 0: 'a', 1: 'b', 2: 'c' }
for (var key in obj) {
  console.log(key) //结果为依次为0,1,2
}

var arr = ['a', 'b', 'c']
for (var key in a) {
  console.log(key) //结果为依次为0,1,2
}

for-ofПредложение выглядит немного похожеfor-inзаявление, но иfor-ofОтличие оператора в том, что он не может перебирать объекты, а только массивы.

var arr = ['a', 'b', 'c']
for (var value of arr) {
  console.log(value) // 结果依次为a,b,c
}

for-ofСравниватьfor-inЛучше зациклиться на массиве.for-ofпока естьIteratorСтруктура данных интерфейса может использоваться для перебора его членов. Он напрямую считывает значение ключа.for-inВсе свойства объекта, которые должны быть исчерпаны, включая пользовательские добавленные свойства, также могут быть пройдены. а такжеfor-inизkeyдаStringТипа, идет процесс конвертации, накладные расходы относительно большие.

Поэтому старайтесь избегать использования циклических массивов в процессе разработки.for-in.

Дедупликация массива

Дедупликация массива часто встречается при реальной разработке и обработке данных, методов много, и я не буду перечислять их здесь по одному.

1. Самый традиционный способ: с помощью массиваindexOfПодпишите свойства для запроса.

function unique4(arr) {
  var newArr = []
  for (var i = 0; i < arr.length; i++) {
    if (newArr.indexOf(arr[i]) === -1) {
      newArr.push(arr[i])
    }
  }
  return newArr
}
console.log(unique4([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))
// [1, 2, 3, 5, 6, 7, 4]

2. Оптимизация: использование ES6Setметод.

Setсам по себе является конструктором, используемым для генерацииSetструктура данных.SetФункции могут принимать массив (или другую структуру данных с помощью интерфейса для инициализации) в качестве параметра для инициализации.SetОбъекты позволяют хранить значения любого типа, будь то примитивное значение или ссылка на объект. Он похож на массив, но значение члена уникально, нет повторяющихся значений.

function unique4(arr) {
  return Array.from(new Set(arr)) // 利用Array.from将Set结构转换成数组
}
console.log(unique4([1, 1, 2, 3, 5, 3, 1, 5, 6, 7, 4]))
// [1, 2, 3, 5, 6, 7, 4]

стрелочная функция

Синтаксис выражений стрелочных функций более лаконичен, чем функциональных выражений. Поэтому в разработке более рекомендуется использовать стрелочные функции. особенно вvueВ проекте с помощью стрелочной функции не нужно обновлятьthisПереназначить переменную.

// 使用functions
var arr = [5, 3, 2, 9, 1]
var arrFunc = arr.map(function (x) {
  return x * x
})
console.log(arrFunc)

// 使用箭头函数
var arr = [5, 3, 2, 9, 1]
var arrFunc = arr.map((x) => x * x)

Обратите внимание, что стрелочные функции не связаныarguments, вместоrestПараметры... разрешены.

// 不能使用 arguments
let fun1 = (b) => {
  console.log(arguments)
}
fun1(2, 92, 32, 32) // Uncaught ReferenceError: arguments is not defined

// 使用rest 参数
let fun2 = (...c) => {
  console.log(c)
}
fun2(3, 82, 32, 11323) // [3, 82, 32, 11323]

Создание Дома

При создании нескольких элементов dom сначала размещайте элементыappendприбытьDocumentFragment, окончательное объединение будетDocumentFragmentдобавил на страницу.

обычный метод;

for (var i = 0; i < 1000; i++) {
  var el = document.createElement('p')
  el.innerHTML = i
  document.body.appendChild(el)
}

использоватьDocumentFragmentоптимизировать несколько разappend

var frag = document.createDocumentFragment()
for (var i = 0; i < 1000; i++) {
  var el = document.createElement('p')
  el.innerHTML = i
  frag.appendChild(el)
}
document.body.appendChild(frag)

Лучший способ: использовать его один разinnerHTMLНазначайте задания вместо создания элементов dom

var html = []
for (var i = 0; i < 1000; i++) {
  html.push('<p>' + i + '</p>')
}
document.body.innerHTML = html.join('')

утечка памяти

Память, которая больше не используется системными процессами и не освобождается вовремя, называется утечкой памяти. Когда использование памяти становится все выше и выше, это повлияет на производительность системы и приведет к сбою процесса.

Причины утечек памяти

глобальная переменная

1. Необъявленная переменная или использованиеthisсозданная переменная (thisуказывает наwindow) вызовет утечку памяти

function fn() {
  a = "Actually, I'm a global variable"
}
fn()

function fn() {
  this.a = "Actually, I'm a global variable"
}
fn()

Решение:

  • Избегайте создания глобальных переменных
  • Чтобы использовать строгий режим, добавьте заголовок файла JavaScript или в начало функции.use strict.

2. В одностраничном приложении vue объявленные глобальные переменные не очищаются при переключении страниц

<template>
  <div id="home">
    这里是首页
  </div>
</template>

<script>
  export default {
    mounted() {
      window.test = {
        // 此处在全局window对象中引用了本页面的dom对象
        name: 'home',
        node: document.getElementById('home')
      }
    }
  }
</script>

Решение: Удаляйте ссылку кстати, когда страница выгружается.

destroyed () {
  window.test = null // 页面卸载的时候解除引用
}

Закрытие

Причины утечек памяти, вызванных замыканиями: замыкания могут поддерживать локальные переменные внутри функций, чтобы их нельзя было освободить.

function fn() {
  var a = "I'm a"
  return function () {
    console.log(a)
  }
}

Решение: Определите внешний обработчик событий, освободите замыкание или удалите ссылку на dom во внешней функции, где определен обработчик событий.

Таймер или прослушиватель событий

Потому что некоторые страницы в проекте неизбежно будут столкнуться с таймерами или мониторинга событий. Однако при выходе из текущей страницы, если таймер не очищается во времени и разумно, он приведет к тому времени бизнес-логики или даже приложение. В это время необходимо очистить слушатель мероприятия таймера, то есть жизненный цикл Функция разгрузки страницы (закрытие). Очистить таймер.

methods:{
  resizeFun () {
    this.tableHeight = window.innerHeight - document.getElementById('table').offsetTop - 128
  },
  setTimer() {
    this.timer = setInterval(() => { })
  },
  clearTimer() {//清除定时器
		clearInterval(this.timer)
    this.timer = null
	}
},
mounted() {
  this.setTimer()
  window.addEventListener('resize', this.resizeFun)
},
beforeDestroy() {
  window.removeEventListener('resize', this.resizeFun)
  this.clearTimer()
}

Защита от тряски и дросселирования

В процессе фронтенд-разработки нам часто приходится привязывать какие-то постоянно срабатывающие события, напримерresize,scroll,mousemoveИ так далее, но иногда мы не хотим выполнять функцию так часто, как событие продолжает срабатывать. В это время используются анти-шейк и троттлинг.

Случай 1: При удаленном поиске необходимо динамически получать данные через интерфейс.Если интерфейс запрашивается для каждого пользовательского ввода, это пустая трата полосы пропускания и производительности.

<Select :remote-method="remoteMethod">
    <Option v-for="item in temoteList" :value="item.value" :key="item.id">{{item.label}}</Option>
</Select>

<script>
function debounce(fn, wait) {
  let timeout = null
  return function () {
    if (timeout !== null) clearTimeout(timeout)
    timeout = setTimeout(fn, wait)
  }
}

export default {
  methods:{
    remoteMethod:debounce(function (query) {
        // to do ...
    }, 200),
  }
}
<script>

Случай 2: непрерывный запускscrollсобытие, не выполненное немедленноhandleфункция, если не срабатывает в течение 1000 мсscrollКогда происходит событие, оно будет запущено один раз с задержкойhandleфункция.

function debounce(fn, wait) {
  let timeout = null
  return function () {
    if (timeout !== null) clearTimeout(timeout)
    timeout = setTimeout(fn, wait)
  }
}
function handle() {
  console.log(Math.random())
}
window.addEventListener('scroll', debounce(handle, 1000))

загружать js асинхронно

По умолчанию браузер загружает js-скрипт синхронно, при разборе html встречается<script>Метка остановится, и после того, как скрипт будет загружен, проанализирован и выполнен, он продолжит анализ и рендеринг вниз.

Если размер js-файла относительно большой, время загрузки будет очень долгим, что легко приведет к блокировке браузера, а на странице браузера будет отображаться эффект «белого экрана», и пользователь почувствует, что браузер "завис" и не отвечает. На этом этапе мы можем позволить скрипту js загружаться и выполняться асинхронно.

<script src="path/to/home.js" defer></script>
<script src="path/to/home.js" async></script>

В приведенном выше коде<script>Этикеткиdeferа такжеasyncproperties, когда браузер распознает эти два свойства, js будет загружаться асинхронно. То есть браузер не будет ждать, пока скрипт будет загружен и выполнен, прежде чем выполнять его в обратном направлении, а продолжит выполняться в обратном направлении напрямую.

Разница между отсрочкой и асинхронностью:

  • defer: структура DOM полностью генерируется, и другие скрипты выполняются до их выполнения (визуализируются, а затем выполняются). иметь более одногоdeferКогда скрипт будет выполнен, он будет загружен и выполнен в том порядке, в котором появляются страницы.
  • async: после завершения загрузки механизм рендеринга прервет рендеринг и после выполнения этого скрипта продолжит рендеринг (выполнить после загрузки). иметь более одногоasyncПри написании сценариев нет гарантии, что страницы будут загружаться и выполняться в том порядке, в котором они появляются.

рекомендуемая статья