Vue 의 nextTick 방법 을 간단하게 이해 합 니 다.

9048 단어 VuenextTick
Vue 의 nextTick 은 Vue 의 DOM 비동기 업데이트 와 관련 되 어 있어 재 미 있 었 습 니 다.특별히 알 아 봤 습 니 다.그 중에서 nextTick 의 소스 코드 는 많은 지식 과 관련 되 고 이해 하지 못 하 는 경우 가 많 으 며 자신의 깨 달 음 에 따라 nextTick 을 소개 합 니 다.
예시
먼저 예 를 들 어 Vue 의 DOM 업데이트 와 nextTick 의 역할 에 대해 알 아 보 겠 습 니 다.
템 플 릿

<div class="app">
 <div ref="msgDiv">{{msg}}</div>
 <div v-if="msg1">Message got outside $nextTick: {{msg1}}</div>
 <div v-if="msg2">Message got inside $nextTick: {{msg2}}</div>
 <div v-if="msg3">Message got outside $nextTick: {{msg3}}</div>
 <button @click="changeMsg">
  Change the Message
 </button>
</div>
Vue 실례

new Vue({
 el: '.app',
 data: {
  msg: 'Hello Vue.',
  msg1: '',
  msg2: '',
  msg3: ''
 },
 methods: {
  changeMsg() {
   this.msg = "Hello world."
   this.msg1 = this.$refs.msgDiv.innerHTML
   this.$nextTick(() => {
    this.msg2 = this.$refs.msgDiv.innerHTML
   })
   this.msg3 = this.$refs.msgDiv.innerHTML
  }
 }
})
클릭 전

클릭 후

그림 에서 알 수 있 듯 이 msg 1 과 msg 3 에 표 시 된 내용 은 변 경 된 것 이 고 msg 2 에 표 시 된 내용 은 변 경 된 것 이다.그 근본 적 인 원인 은 Vue 에서 DOM 업데이트 가 비동기 적 이기 때문이다.
2.응용 장면
다음은 nextTick 의 주요 응용 장면 과 원인 을 알 아 보 겠 습 니 다.
Vue 라 이 프 사이클 의 created()갈고리 함수 에서 진행 되 는 DOM 작업 은 Vue.nextTick()의 리 셋 함수 에 넣 어야 합 니 다.
created()갈고리 함수 가 실 행 될 때 DOM 은 렌 더 링 을 하지 않 았 습 니 다.이때 DOM 작업 을 하 는 것 은 헛 된 것 이 아니 므 로 DOM 작업 의 js 코드 를 Vue.nextTick()의 리 셋 함수 에 넣 어야 합 니 다.이에 대응 하 는 것 은 mounted()갈고리 함수 입 니 다.이 갈고리 함수 가 실 행 될 때 모든 DOM 마 운 트 와 렌 더 링 이 완료 되 었 기 때문에 이 갈고리 함수 에서 어떠한 DOM 작업 도 문제 가 되 지 않 습 니 다.
데이터 가 변 한 후에 실행 할 동작 입 니 다.이 동작 은 데이터 에 따라 변 경 된 DOM 구 조 를 사용 해 야 할 때 이 동작 은 모두 Vue.nextTick()의 리 셋 함수 에 넣 어야 합 니 다.
구체 적 인 원인 은 Vue 의 공식 문서 에서 상세 하 게 설명 한다.
Vue 비동기 로 DOM 업 데 이 트 를 실행 합 니 다.데이터 변 화 를 관찰 하면 Vue 는 하나의 대기 열 을 열 고 같은 이벤트 순환 에서 발생 하 는 모든 데이터 변 화 를 버퍼 링 합 니 다.같은 watcher 가 여러 번 트리거 되면 대기 열 에 한 번 만 추 가 됩 니 다.버퍼 링 을 할 때 중복 데 이 터 를 제거 하 는 것 은 불필요 한 계산 과 DOM 작업 을 피 하 는 데 매우 중요 하 다.그리고 다음 이벤트 순환"tick"에서 Vue 가 대기 열 을 새로 고치 고 실제(무 거 운 것)작업 을 수행 합 니 다.Vue 는 내부 에서 비동기 대기 열 에 원생 Promise.then 과 MessageChannel 을 사용 하려 고 시도 하 며,실행 환경 이 지원 되 지 않 으 면 setTimeout(fn,0)으로 대체 합 니 다.
예 를 들 어 vm.somedata='new value'를 설정 하면 이 구성 요 소 는 바로 렌 더 링 되 지 않 습 니 다.대기 열 을 새로 고 칠 때 구성 요 소 는 이벤트 순환 대기 열 이 비어 있 을 때 다음"tick"을 업데이트 합 니 다.대부분의 경우 우 리 는 이 과정 에 관심 을 가 질 필요 가 없 지만,DOM 상태 가 업 데 이 트 된 후에 무엇 을 하고 싶다 면 좀 까다 로 울 수 있다.Vue.js 는 개발 자 들 이'데이터 구동'방식 으로 생각 하고 DOM 과 직접 접촉 하지 않도록 격려 하지만 가끔 우 리 는 이렇게 해 야 한다.데이터 가 변 한 후 Vue 가 DOM 업 데 이 트 를 완료 할 때 까지 기다 리 기 위해 서 는 데이터 가 변 한 후 바로 Vue.nextTick(callback)을 사용 할 수 있 습 니 다.이렇게 리 셋 함 수 는 DOM 업데이트 가 완료 되면 호출 됩 니 다.
3.nextTick 소스 코드 에 대한 분석
역할.
Vue.nextTick 은 코드 실행 을 지연 시 키 는 데 사 용 됩 니 다.2 개의 인자(리 셋 함수 와 리 셋 함 수 를 실행 하 는 컨 텍스트 환경)를 받 아들 입 니 다.리 셋 함 수 를 제공 하지 않 으 면 promise 대상 으로 돌아 갑 니 다.
소스 코드

/**
 * Defer a task to execute it asynchronously.
 */
export const nextTick = (function () {
 const callbacks = []
 let pending = false
 let timerFunc

 function nextTickHandler () {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
   copies[i]()
  }
 }

 // the nextTick behavior leverages the microtask queue, which can be accessed
 // via either native Promise.then or MutationObserver.
 // MutationObserver has wider support, however it is seriously bugged in
 // UIWebView in iOS >= 9.3.3 when triggered in touch event handlers. It
 // completely stops working after triggering a few times... so, if native
 // Promise is available, we will use it:
 /* istanbul ignore if */
 if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError)
   // in problematic UIWebViews, Promise.then doesn't completely break, but
   // it can get stuck in a weird state where callbacks are pushed into the
   // microtask queue but the queue isn't being flushed, until the browser
   // needs to do some other work, e.g. handle a timer. Therefore we can
   // "force" the microtask queue to be flushed by adding an empty timer.
   if (isIOS) setTimeout(noop)
  }
 } else if (!isIE && typeof MutationObserver !== 'undefined' && (
  isNative(MutationObserver) ||
  // PhantomJS and iOS 7.x
  MutationObserver.toString() === '[object MutationObserverConstructor]'
 )) {
  // use MutationObserver where native Promise is not available,
  // e.g. PhantomJS, iOS7, Android 4.4
  var counter = 1
  var observer = new MutationObserver(nextTickHandler)
  var textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
   textNode.data = String(counter)
  }
 } else {
  // fallback to setTimeout
  /* istanbul ignore next */
  timerFunc = () => {
   setTimeout(nextTickHandler, 0)
  }
 }

 return function queueNextTick (cb?: Function, ctx?: Object) {
  let _resolve
  callbacks.push(() => {
   if (cb) {
    try {
     cb.call(ctx)
    } catch (e) {
     handleError(e, ctx, 'nextTick')
    }
   } else if (_resolve) {
    _resolve(ctx)
   }
  })
  if (!pending) {
   pending = true
   timerFunc()
  }
  if (!cb && typeof Promise !== 'undefined') {
   return new Promise((resolve, reject) => {
    _resolve = resolve
   })
  }
 }
})()

우선,nextTick 에서 정의 하 는 세 가지 중요 한 변 수 를 알 아 보 세 요.
  • callbacks:실행 해 야 할 모든 리 셋 함 수 를 저장 합 니 다
  • pending:리 셋 함수 가 실행 되 고 있 는 지 여 부 를 표시 하 는 데 사 용 됩 니 다
  • timerFunc:실행 반전 함 수 를 촉발 합 니 다
  • 다음은 nextTickHandler()함 수 를 알 아 보 겠 습 니 다.
    
    function nextTickHandler () {
      pending = false
      const copies = callbacks.slice(0)
      callbacks.length = 0
      for (let i = 0; i < copies.length; i++) {
       copies[i]()
      }
     }
    
    이 함 수 는 콜 백 스에 저 장 된 모든 리 셋 함 수 를 실행 하 는 데 사 용 됩 니 다.
    다음은 트리거 방식 을 timerFunc 에 할당 합 니 다.
    원생 지원 promise 여 부 를 먼저 판단 하고 지원 하면 promise 를 이용 하여 리 셋 함 수 를 실행 합 니 다.
    그렇지 않 으 면 MutationObserver 를 지원 하면 관찰자 대상 을 예화 하고 텍스트 노드 의 변 화 를 관찰 할 때 모든 리 셋 함 수 를 실행 합 니 다.
    지원 되 지 않 으 면 setTimeout 설정 을 0 으로 지연 합 니 다.
    마지막 으로 queue NextTick 함수 입 니 다.nextTick 은 실시 간 함수 이기 때문에 quueNextTick 함 수 는 되 돌아 오 는 함수 입 니 다.사용자 가 들 어 오 는 인 자 를 받 아들 여 콜백 스에 리 셋 함 수 를 저장 합 니 다.

    위의 그림 은 전체 실행 프로 세 스 입 니 다.관건 은 timeFunc()입 니 다.이 함 수 는 실행 을 지연 시 키 는 역할 을 합 니 다.
    위의 설명 을 통 해 알 수 있 듯 이 timeFunc()는 모두 세 가지 실현 방식 이 있다.
  • Promise
  • MutationObserver
  • setTimeout
  • 그 중에서 Promise 와 setTimeout 은 이해 하기 쉽 고 비동기 작업 으로 동기 화 작업 과 DOM 의 비동기 작업 을 업데이트 한 후에 구체 적 인 함 수 를 되 돌려 줍 니 다.
    다음은 Mutation Observer 에 중심 을 두 고 소개 하 겠 습 니 다.
    MutationObserver 는 HTML 5 의 새 API 로 DOM 변동 을 감시 하 는 인터페이스 입 니 다.그 는 DOM 대상 에서 발생 하 는 하위 노드 삭제,속성 수정,텍스트 내용 수정 등 을 감청 할 수 있다.
    호출 과정 은 매우 간단 하지만,좀 심상 치 않다.너 는 먼저 그 에 게 리 셋 을 해 야 한다.
    
    var mo = new MutationObserver(callback)
    Mutation Observer 의 구조 함수 에 리 셋 을 전달 하면 Mutation Observer 인 스 턴 스 를 얻 을 수 있 습 니 다.이 리 셋 은 Mutation Observer 인 스 턴 스 가 변동 을 감청 할 때 실 행 됩 니 다.
    이때 당신 은 Mutation Observer 인 스 턴 스 에 리 셋 을 연결 시 켰 을 뿐 어떤 DOM,감청 노드 가 삭제 되 었 는 지,감청 속성 이 수정 되 었 는 지 구체 적 으로 감청 하 였 을 뿐 설정 되 지 않 았 습 니 다.그의 observer 방법 을 호출 하면 이 단 계 를 완성 할 수 있다.
    
    var domTarget =       dom  
    mo.observe(domTarget, {
       characterData: true //           。
    })
    
    

    nextTick 에서 Mutation Observer 의 역할 은 위의 그림 과 같다.DOM 업 데 이 트 를 감청 한 후 리 셋 함 수 를 호출 합 니 다.
    사실 Mutation Observer 를 사용 하 는 이 유 는 nextTick 이 비동기 API 를 원 하기 때 문 입 니 다.현재 동기 코드 가 실 행 된 후에 제 가 실행 하고 싶 은 비동기 리 셋 을 실행 하 는 데 사 용 됩 니 다.Promise 와 setTimeout 을 포함 한 것 은 모두 이 때 문 입 니 다.그 중에서 도 microtask 등 내용 이 깊이 있 고 이해 하지 못 하면 깊이 소개 하지 않 습 니 다.
    이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

    좋은 웹페이지 즐겨찾기