반응형

v-for을 사용하다보면 생각보다 요놈이 문제 많은 녀석이라는걸 느낄 때가 있다.

그런데 국내나 해외나 이 v-for에 대해서 제대로 적어놓은 녀석이 별로 없는거 같다.

그냥 불편해도 사용하는건지...

사용시 주의를 요하는 녀석인데 그 이유에 대해서 논해보도록 하자.

 

 

코딩을 하다보면 v-for은 안쓸래야 안쓸 수가 없다.

굉장히 좋은녀석이지만 몇가지 문제점이 존재한다.

 

일단. v-for은 해당 데이터의 길이가 0이면 그리지 않는다.

그래서 굳이 v-if를 달 필요가 없다는건 장점이다.

 

하지만 문제는 길이가 가변할 경우이다.

 

대부분 v-for의 문제는 가변하는 길이에서 오는 것이다.

v-for에서 데이터를 처리하는 방식은 아래와 같다.(완벽하게 같지는 않고 얼추 맞음)

 

1. data의 길이가 0(혹은 초기화)에서 n의 길이가 되었을 경우 n개의 컴포넌트를 만들고 dom으로 바꾼다.

2. 1번 이후 당연히 컴포넌트는 새로 만들어졌으므로(dom으로 인스턴스화 됬으므로) created와 mounted 이벤트가 발생

3. data의 길이가 n개에서 m개로 증가 되었다.(m은 n보다 크다)

4. 3번 이후 컴포넌트가 추가되었지만 기존의 dom자체를 파기하지는 않고 적절히 순서를 유지한다.(새 데이터가 앞일지 뒤일지 중간일지 모르므로)

5. 데이터가 당연히 추가되야하므로 m-n개 만큼 추가로 dom을 생성한다 당연히 추가로 생성된 컴포넌트는 created와 mounted가 발생한다. 

 

여기서 눈여겨 볼것은 데이터가 추가되었을 때 기존의 dom을 파기하지 않는다는것, 이말은 기존의 컴포넌트를 파기하지 않는다는 말과 동의어다.

 

그렇기 때문에 데이터가 늘어나서 추가로 돔이 생겨도 기존의 dom이 파기되지는 않았으므로 이벤트는 발생하지 않는다.

싹 재 렌더링을 하지 않기 때문에 당연히 성능이 상승하게 된다.

 

여기서 문제점이 발생하는 경우가 많다.

 

이 때 발생하는 문제점

 

일단 이 문제점 보다 이번에는 key에 초점을 맞춰보도록 하자.

 

이 때까지 위의 이야기는 다 key의 역활을 말하기 위해서 한것이다.

4번에 dom자체를 파기하지 않고 적절한 순서를 유지하는것은 바로 key때문에 가능하다.

데이터가 다시 업데이트 될 때 가상돔과 돔의 key를 비교한다.

key가 지정되어있다면 이 key를 통해서 특정 녀석을 "재 렌더링 할지"정하게 된다.

key가 없다고 반드시 재 랜더링을 하는것은 아닌거 같다.(필자의 테스트결과)

하지만 key가 겹치게된다면 매우 높은 확률로 재 렌더링을 한다는 것이다.

 

※아 그리고 key가 없으면 인덱스를 그냥 key로 넣는다는 주장이 있다. 주장인데 신빙성은 있는 듯.

 

이는 몇가지 테스트를 통하여 확인하였다.

 

테스트 조건은 아래와 같다.

 

데이터 앞에 신 데이터 끼워넣기

 

1. 크기와 색, 위치는 렌덤인 div에 숫자를 넣는다. 갯수는 1만개이다.

2. 3초후에 1만개의 div를 추가적으로 기존 데이터의 앞에 추가한다.(즉 배열은 2만개가 되고 앞의 1만개는 신데이터, 과거 1만개는 구데이터)

3. 그 후 과거 1만개가 생성된 직후에서 새로 1만개가 생성된 직후의 간차이를 계산한다.

4. 3개의 대조군을 만드는데 하나는 key가 없는 녀석, 하나는 key가 있지만 중복이 발생하는 녀석, 하나는 key가 있고 유니크한 녀석이다.

 

이렇개 개발자 도구 켜서 총 걸리는 시간을 확인하겠다는 뜻이다.

 

 

그럼 실험 결과를 공개하겠다. 단위는 초이다.

 

key가 없는 경우 => 3.92 3.81 3.92 3.94 4.10

key가 있지만 유니크하지 않음 => 3.68 3.77 3.63 3.66 3.72

key가 있고 유니크함 => 3.55 3.47 3.58 3.58 3.36

 

평균을 내보면

 

key(없음) = 3.93

key(중복) = 3.69

key(유니크) = 3.5

 

키가 없는것 보다는 중복되더라도 있는게 빨랐고 중복된것보단 유니크한게 빨랐다.

하지만 여기서 함정이 있는데 위의 경우에는 데이터의 순서가 유지가 됬기 때문에 중복이 되어도 재 렌더링이 거의(혹은 전혀)일어나지 않는다.

아마 vue에서 과거데이터와의 대조를 통하여 key가 없어도 어느정도 캐싱효과를 보장해주는것 같다.

일반적인 경우에는 중복된다면 없는게 더 나은데 그 이유는 아래를 보면 알 수 있다.

실험 방식을 약간 바꿔보자.

 

과거 데이터와 신 데이터를 교차로 섞기

 

1. 크기와 색, 위치는 렌덤인 div에 숫자를 넣는다. 갯수는 1만개이다.

2. 3초후에 1만개의 div를 추가적으로 기존 데이터와 셔플하듯이 사이에 교차로 추가한다.(즉 배열은 2만개가 되고 앞의 1만개는 신데이터, 과거 1만개는 구데이터)

3. 그 후 과거 1만개가 생성된 직후에서 새로 1만개가 생성된 직후의 간차이를 계산한다.

 

4. 3개의 대조군을 만드는데 하나는 key가 없는 녀석하나는 key가 있지만 중복이 발생하는 녀석하나는 key가 있고 유니크한 녀석이다.

 

이 경우 어떻게 될까?

놀랍게도 결과는 이상하게 전개된다.

 

key가 없는 경우 => 3.99 4.00 3.88 4.01 4.04

key가 있지만 유니크하지 않음 => 5.7 5.53 5.10 5.23 5.29

key가 있고 유니크함 => 3.60 3.58 3.63 3.56 3.63

 

평균을 내보면

 

key(없음) = 3.98

key(중복) = 5.37

key(유니크) = 3.6

 

오히려 키가 중복될 때 성능이 눈에 띄게 하락하는 것을 확인할 수 있다.

그 이유는 제랜더링이 눈에 띄게 많이 일어나는데 이는 아래의 그림을 보면 알 수 있다.

 

사진속 마우스 커서가 새로 고침을 누른 시점에서 확인하라!

 

key가 없는 경우이다.

 

key가 있고 중복되지 않는 경우이다.

 

key가 있는데 중복되는 경우이다.

 

뭔가 차이가 느껴지는가?

위의 둘은 기존 컴포넌트(돔)이 사라지지 않고 추가만 됬지만 key중복이 있는 경우 몇개는 없어지고 재 렌더링이 된다.

일종의 캐싱 효과를 못 받는걸로 해석된다.

 

애당초 key가 중복된다는 것은 일종의 버그이다. "특정 상황에서 key가 있을 때 없을 때"의 성능이 다르긴하지만

그걸 논하는건 무의미하며 정의된 스펙이 아니다. 따라서 그냥 key는 유니크하게 만들어야한다.

 

결론

 

1. key는 성능에 영향을 확실하게 미친다.

2. key가 없는 경우 데이터가 삽입 정도와 정렬정도에 따라서 캐싱효과를 보고 못보고가 결정된다.

3. key가 중복되는데 캐싱을 못볼경우 그냥 재 렌더링 해버리는데 그 사이드 이펙트가 클 수도 있다.

4. key를 쓸꺼면 아예 중복안되게 key를 만들고 안 쓸거면 그냥 쓰지 않는게 낫다.

 

결론 중의 결론

 

그냥 key쓰세요. 아 그리고 무조건 유니크하게

 

key가 없을 때는 사실 필자가 테스트할 땐 제 랜더링이 일어난 적이 없는데 더 뚜렷하게 아시는 분이 알려주시면 감사하겠다.

 

출처: https://kamang-it.tistory.com/entry/WebPerformanceVue-vfor%EA%B3%BC-key-%EA%B7%B8%EB%A6%AC%EA%B3%A0-%EC%84%B1%EB%8A%A5%EC%82%AC%EC%9D%B4%EC%9D%98-%EA%B4%80%EA%B3%84

반응형
반응형

Vue.js의 라이프 사이클은 크게 Creation, Mounting, Updating, Destruction 으로 나눌 수 있다.

1. Creation : 컴포넌트 초기화 단계

Creation 단계에서 실행되는 훅(hook)들이 라이프사이클 중에서 가장 처음 실행된다. 이 단계는 컴포넌트가 돔에 추가되기 전이다. 서버 렌더링에서도 지원되는 훅이다.

따라서 클라이언트 단과 서버단 렌더링 모두에서 처리해야할일이 있다면 이단계에서 하면된다. 아직 컴포넌트가 돔에 추가되기 전이기 때문에 돔에 접근하거나 this.$el를 사용할 수 없다.

이 단계에서는 beforeCreate 훅과 Created 훅이 있다.

beforeCreate

모든 훅 중에 가장 먼저 실행되는 훅이다. 아직 data와 events(vm.$on, vm.$once, vm.$off, vm.$emit)가 세팅되지 않은 시점이므로 접근하려고 하면 에러를 뿜어낼 것이다.

<script>
  export default {
    data () {
      return {
        title: ''
      }
    },

    beforeCreate () {
      //can't use Data(this.title ...), events(vm.$on, vm.$once, vm.$off, vm.$emit)
    }
  }
</script>

 

created

created 훅에서는 이제 data와 events가 활성화되어 접근할 수 있다. 여전히 템플릿과 가상돔은 마운트 및 렌더링되지 않은 상태이다.

<script>
  export default {
    data () {
      return {
        title: ''
      }
    },
    computed: {
      titleComputed() {
        console.log('I change when this.property changes.')
        return this.property
      }
    },
    created () {
      //can use Data(this.title, this.titleComputed ...), events(vm.$on, vm.$once, vm.$off, vm.$emit)
      //don't use $el
    }
  }
</script>

2. Mounting : 돔(DOM) 삽입 단계

Mounting 단계는 초기 렌더링 직전에 컴포넌트에 직접 접근할 수 있다. 서버렌더링에서는 지원하지 않는다.

초기 랜더링 직전에 돔을 변경하고자 한다면 이 단계를 활용할 수 있다. 그러나 컴포넌트 초기에 세팅되어야할 데이터 페치는 created 단계를 사용하는것이 낫다.

beforeMount

beforeMount 훅은 템플릿과 렌더 함수들이 컴파일된 후에 첫 렌더링이 일어나기 직전에 실행된다. 대부분의 경우에 사용하지 않는 것이 좋다. 그리고 서버사이드 렌더링시에는 호출되지 않는다.

<script>
export default {
  beforeMount() {
    console.log(`this.$el doesn't exist yet, but it will soon!`)
  }
}
</script>

mounted

mounted 훅에서는 컴포넌트, 템플릿, 렌더링된 돔에 접근할 수 있다. 모든 하위 컴포넌트가 마운트된 상태를 보장하지는 않는다. 서버렌더링에서는 호출되지 않는다.

<script>
export default {
  mounted() {
    console.log(this.$el.textContent) // can use $el
    this.$nextTick(function () {
      // 모든 화면이 렌더링된 후 실행합니다.
    })
  }
}
</script>

mounted 훅에서 유의할 점은, 부모와 자식 관계의 컴포넌트에서 우리가 생각한 순서로 mounted가 발생하지 않는다는 점이다. 즉 부모의 mounted훅이 자식의 mounted훅보다 먼저 실행되지 않는다. 오히려 그 반대이다.

Parent/child initialisation workflow

위 그림처럼 Created훅은 부모->자식의 순서로 실행되지만 mounted는 그렇지 않다는 것을 알 수 있다. 다른 식으로 말하면 부모는 mounted훅을 실행하기 전에 자식의 mounted훅이 끝나기를 기다린다. (참고 Vue Parent and Child lifecycle hooks)

3. Updating : Diff 및 재 렌더링 단계

컴포넌트에서 사용되는 반응형 속성들이 변경되거나 어떤 이유로 재 렌더링이 발생되면 실행된다. 디버깅이나 프로파일링 등을 위해 컴포넌트 재 렌더링 시점을 알고 싶을때 사용하면 된다. 조심스럽지만, 꽤 유용하게 활용될 수 있는 단계이다. 서버렌더링에서는 호출되지 않는다.

beforeUpdate

이 훅은 컴포넌트의 데이터가 변하여 업데이트 사이클이 시작될때 실행된다. 정확히는 돔이 재 렌더링되고 패치되기 직전에 실행된다. 재 렌더링 전의 새 상태의 데이터를 얻을 수 있고 더 많은 변경이 가능하다. 이 변경으로 이한 재 렌더링은 트리거되지 않는다.

updated

이 훅은 컴포넌트의 데이터가 변하여 재 렌더링이 일어나 후에 실행된다. 돔이 업데이트 완료된 상태이므로 돔 종속적인 연산을 할 수 있다. 그러나 여기서 상태를 변경하면 무한루프에 빠질 수 있다. 모든 자식 컴포넌트의 재 렌더링 상태를 보장하지는 않는다.

<script>
export default {
  updated() {
    this.$nextTick(function () {
      // 모든 화면이 렌더링된 후 실행합니다.
    })
  }
}
</script>

4. Destruction : 해체 단계

beforeDestroy

이 훅은 해체(뷰 인스턴스 제거)되기 직전에 호출된다. 컴포넌트는 원래 모습과 모든 기능들을 그대로 가지고 있다. 이벤트 리스너를 제거하거나 reactive subscription을 제거하고자 한다면 이 훅이 제격이다. 서버 렌더링시 호출되지 않는다.

destroyed

이 훅은 해체(뷰 인스턴스 제거)된 후에 호출된다. Vue 인스턴스의 모든 디렉티브가 바인딩 해제 되고 모든 이벤트 리스너가 제거되며 모든 하위 Vue 인스턴스도 삭제된다. 서버 렌더링시 호출되지 않는다.

그 밖에

activated와 deactivated가 있다. 각각 keep-alive 컴포넌트가 활성화 될 때와 비활성화 될 때 호출된다.

 

출처: https://medium.com/witinweb/vue-js-%EB%9D%BC%EC%9D%B4%ED%94%84%EC%82%AC%EC%9D%B4%ED%81%B4-%EC%9D%B4%ED%95%B4%ED%95%98%EA%B8%B0-7780cdd97dd4

반응형
반응형

https://www.youtube.com/watch?v=vqwe1H1cYrY

이 유튜브가 여러곳중에 제일 친절하고 이해하기 쉬웠다.

반응형
반응형

JavaScript가 될 언어의 첫 번째 데모는 거의 정확히 25 년 전에 진행되었습니다 .

이 언어는 1995 년 가을 Netscape Navigator 베타에서 LiveScirpt로 출시되었으며 그해 말에 JavaScript로 이름이 변경되었습니다. 그해 말에 저는 JavaScript : The Definitive Guide 의 첫 번째 판 (O'Reilly에서이를 "베타 판" 으로 출판)을 시작했으며 1996 년 8 월에 출판되었습니다. .

 일곱 번째 에디션이 몇 주에 나오고, 나는 자바 스크립트의 우리가 지금, 자비, 잊을 수있는 초기 웹 플랫폼의 오래된 이상한 기능에 대한 기억을 더듬어 및 블로그 다운 여행을하고 싶다. 새 7 번째 에디션이 6 번째 에디션보다 얇은 이유 중 하나는 참조 섹션을 제거 했기 때문 입니다. 그러나 2020 년에는 더 이상 웹 개발자와 관련이없는 것들이 많았습니다. 웹 호환성은 영원히 (또는 25 년 이상) 지속되므로 브라우저 공급 업체는 오래되고 모호한 지원을 계속해야 할 수 있습니다 언어 및 플랫폼 기능이 오랫동안 사용되었습니다. 그러나 우리 나머지는 더 이상 우리의 마음을 어지럽 힐 필요가 없습니다.

여기에 더 이상 JavaScript : Definitive Guide 의 페이지 수를 늘리지 않는 JavaScript 및 웹 플랫폼 기능이 있습니다. 그들에게 작별 인사를하게되어 기쁩니다. (나는 여기에 약간의 맹렬한 소리가 나고 있다고 느낀다. 따라서 이것이 신중하게 연구되지는 않았고, 나쁜 옛날 시절의 일에 대한 내 기억 만 경고된다.)

  • arguments개체가 완전히의 도입에 의해 없어진다 된 ...argsES6있다. 명명 된 인수와 상호 작용하는 이상한 방식을 설명하고 성능 관련 사항에 대해 항상주의를 기울이는 것은 항상 어려운 일이었습니다. 레거시 코드에서 여전히 볼 수 있으며 arguments엄격 모드에서 로컬 변수 또는 함수 매개 변수의 이름을 지정하려고하면 존재 여부를 상기시킬 수 있지만 이제 나머지 인수가 있으므로 망각에 빠질 수 있어야합니다.

  • 우리는 반복 된 문자열 연결의 성능에 대해 걱정해야했습니다. 우리 모두는 문자열을 배열로 푸시 join()하고 마지막에 모든 것을 연결 하는  사용하는 기간이있었습니다 . 그런 다음 JavaScript가 빨라지고 우리는 모두“실제로”그 패턴을 배우지 못했습니다. 그리고 이제 더 이상 문자열 연결을 사용하는 템플릿 리터럴이 있습니다!

  • document.write()DOM 이전에 JavaScript의 주요 기능이었습니다. (20 세기에 JavaScript를 사용하지 않았다면 DOM 이전에 시간이 있었음을 알 수는 있지만 사실입니다. 웹 페이지의 배경색을 변경하도록 설정할 수있는 속성이 있었지만 그 방법은 없습니다 IIRC를 사용하여을 사용하여 문서에 스크립트를 삽입 할 수도 document.write()있지만 </script>HTML 파서가이를 해석하지 않도록 닫는 태그를 두 개의 문자열로 분리해야합니다. 현재 실행중인 스크립트의 끝

  • HTML은하지 않았다 <iframe>초기에,하지만 거기 <frameset>와 <frame>.  window.frames속성은 문서의 프레임을 나타내는 중첩 창 객체의 배열이었습니다. 실제로 open()프레임에서 문서  메서드를 호출 한 다음 document.write()해당 프레임 내에서 전체 문서를 동적으로 생성하는 데 사용할 수있었습니다. 실제로는 시원했습니다. 프레임은 다른 프레임 안에 중첩 될 수 있으므로 모든 Window 객체에는 frames자식 프레임을 포함 하는 배열과 parent포함 창 top을 참조 하는 속성  최상위 창을 참조 하는 속성이 있습니다. 필자의 저서 초판은 긴 부분과이 모든 것을 설명하는 복잡한 그림을 다뤘습니다.

  • 문서 내의 특정 요소를 참조하기위한 모든 종류의 사용되지 않는 기술이 있습니다. frames배열이 또한 있었다, IIRC 일 이었지만, links그리고 images말 그대로 문서에있는 모든 링크와 이미지의 단지 목록이었다 아니라 배열. IE (버전 4, 나는 생각한다)는 document.all문서에 모든 요소의 배열을 올인 하고 소개했다 . (이것은 DOM과 "DHTML"의 시작이었습니다. 마른 땅으로 기어가는 최초의 물고기와 같은 종류였습니다.) document.all온갖 이상한 기능이있었습니다. 이름이나 다른 요소로 요소를 찾는 방법도있는 배열이었습니다. 그렇게 document.all표준화 없지만, 심지어 표준 방법 좋아 않았다 document.getElementById(), document.getElementsByName(), document.getElementsByTagName()와 document.getElementsByClassName()jQuery의에 의해 부적절로 분쇄되지 않는 오늘을 보인다$()기능과 그것이 영감을 얻은 표준 document.querySelector()및 document.querySelectorAll()방법. CSS 선택기의 강력한 기능을 통해이 두 기능은 이전의 모든 기능을 폐기합니다.

  • Internet Explorer에서 가장 싫어했던 것은 attachEvent()이벤트 핸들러 등록 방법을 사용했다는 것 입니다. 내 기억에, 그들은 표준이지만이 작업을 수행addEventListener()이미 정의되었고, 정말 저를 괴롭 혔습니다. 이벤트와 이벤트 처리는 웹에서 가장 큰 비 호환성 소스 중 하나였으며, 수 년 동안 JavaScript 프로그래머 (및 JavaScript 서적 저자)는 IE 이벤트 모델과 표준 이벤트 모델 간의 긴 차이 목록을 처리해야했습니다. 이벤트 처리 코드는 IE와 Firefox에 대해 두 번 작성해야했습니다. 사건에 관한 서적 장은 사건을 다루는 두 가지 유사하지만 완전히 양립 할 수없는 방법이 있었기 때문에 필요한 것보다 두 배나 길었습니다. jQuery의 주요 기능 중 하나는 자체 이벤트 호환성 계층을 구현하여 jQuery 이벤트에 대해서만 알아야한다는 것이 었습니다. 이것이 인기의 중요한 이유라고 생각합니다.

  • 원래 DOM API는 XML에 대한 마 법적 사고 시대에 정의되었습니다. (사람들은 XML이 모든 데이터 문제를 해결할 것이라고 몇 년 동안 믿었던 것 같았습니다. 이상한 시간이었습니다.) 어떻게 든 W3C는 DOM API를 정의했다고 Java 사람들이 침투했다고 약속했습니다. HTML 문서로 작업하는 JavaScript 프로그래머 및 XML 데이터로 작업하는 Java 프로그래머가 사용하는 단일 API. 그렇기 때문에 Attr 노드와 같은 이상한 것들이 가장 좋은 이유입니다. DOM Level 3 API에 대해 항상 나를 괴롭혔던 것 중 하나는 e문서에서 요소를 제거하면 e.remove()오늘날처럼 쓸 수 없다는 것입니다. 당신은 실제로 썼다 e.parentNode.removeChild(e).

 

원문 : https://davidflanagan.com/2020/05/12/javascript-to-forget.html

반응형

+ Recent posts