Javascript 프런트엔드 최적화 코드

if 판단의 최적화


JavaScript 조건 문장은 우리가 평소에 개발하는 과정에서 불가피하게 사용해야 하지만 많은 경우 우리의 코드를 잘 쓰지 못한다. 일련의 if-else나 다중 삽입 판단은 코드를 비대하게 할 수 있다. 다음은 최적화를 예로 들 수 있다.
수요: 현재 4개의 제품이 있는데 각각 휴대전화, 컴퓨터, 텔레비전, 게임기입니다. 물론 제품마다 가격이 다릅니다.

1. 가장 간단한 방법:if판단


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. 더 나은 방법: 전략 모델


전략 모델은 조합, 위탁과 다태적 등 기술과 사상을 이용하여 다중 조건의 문장 선택을 효과적으로 피할 수 있다.이것은 개방-폐쇄 원칙에 대한 완벽한 지원을 제공하고 알고리즘을 독립된strategy에 봉하여 전환하기 쉽고 이해하기 쉽고 확장하기 쉽다.

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

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

includes의 최적화


includes는 ES7에 추가된 API입니다. indexOf와 달리 includes는 Boolean 값을 직접 되돌려주고 indexOf는 색인 값을 되돌려줍니다. 그룹과 문자열은 모두 includes 방법이 있습니다.
수요: 신분 인증 방법을 실현하여 신분 Id를 전송하여 대응하는 검증 결과를 되돌려줍니다
전통적인 방법

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 ' '
  }
}

for 순환


자바스크립트에서 우리는 for (),while (), for (in), for (in) 몇 가지 순환을 사용할 수 있다. 사실 이 세 가지 순환 중 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의 키는 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, 최적화: ES6의 Set 방법을 사용합니다.


Set 자체는 Set 데이터 구조를 생성하는 데 사용되는 구조 함수입니다.Set 함수는 하나의 수조 (또는iterable 인터페이스가 있는 다른 데이터 구조) 를 매개 변수로 받아들여 초기화할 수 있습니다.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 생성


여러 개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)
더 좋은 방법:dom 요소 구축 대신 innerHTML 값 사용하기

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

메모리 유출


시스템 프로세스가 더 이상 사용하지 않는 메모리를 제때에 방출하지 않으면 메모리 유출 (memory leak) 이라고 합니다.메모리의 사용량이 갈수록 높아지면 가벼워지면 시스템 성능에 영향을 주고 무겁면 프로세스가 붕괴된다.
메모리 유출을 일으키는 원인
전역 변수

1. 설명되지 않은 변수나this로 만든 변수 (this의 지향은 윈도우) 는 메모리 유출을 일으킬 수 있습니다


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을 해석하는 과정에서 라벨을 만나면 멈추고 스크립트를 다운로드, 해석, 실행한 후에 계속 아래로 렌더링을 해석합니다.
    만약에 js 파일의 부피가 비교적 크면 다운로드 시간이 길고 브라우저가 막히기 쉬우며 브라우저 페이지는'흰색 화면'효과를 나타내고 사용자는 브라우저가 끊겼다고 느끼며 응답이 없다.이 때, 우리는 js 스크립트를 비동기적으로 불러오고 실행할 수 있습니다.
    
    <script src="path/to/home.js" defer></script>
    <script src="path/to/home.js" async></script>
    위 코드에서 라벨은 각각 defer와 async 속성이 있습니다. 브라우저가 이 두 속성을 식별하면 js가 비동기적으로 불러옵니다.즉, 브라우저는 이 스크립트를 다운로드하고 실행한 후에 뒤로 실행하는 것을 기다리지 않고 바로 뒤로 실행한다
    defer와 async의 차이점:
  • defer: DOM 구조가 완전히 생성되고 다른 스크립트가 실행되어야 실행됩니다(렌더링된 후 실행).여러 개의 defer 스크립트가 있을 때, 페이지가 나타나는 순서에 따라 순서대로 불러오고 실행합니다..
  • async: 다운로드가 완료되면 렌더링 엔진이 렌더링을 중단합니다. 이 스크립트를 실행한 후에 계속 렌더링합니다. (다운로드가 끝나면 실행합니다.)여러 개의 async 스크립트가 있을 때, 페이지의 순서에 따라 불러오고 실행하는 것을 보장할 수 없습니다
  • 이상은 자바스크립트 전단 최적화 코드의 상세한 내용입니다. 자바스크립트 최적화에 대한 더 많은 자료는 저희 다른 관련 글을 주목해 주십시오!

    좋은 웹페이지 즐겨찾기