>  기사  >  웹 프론트엔드  >  Vue.nextTick 구현 방법에 대한 자세한 설명

Vue.nextTick 구현 방법에 대한 자세한 설명

小云云
小云云원래의
2018-01-22 10:06:361364검색

이 글은 주로 Vue.nextTick의 구현 방법을 소개합니다. 편집자는 이것이 꽤 좋다고 생각합니다. 이제 여러분과 공유하고 참고할 것입니다. 편집자를 따라 살펴보겠습니다. 모두에게 도움이 되기를 바랍니다.

이벤트 루프와 MicroTask에 따른 vue.nextTick API 구현의 소스 코드 분석입니다.

준비 및 절전 기능 작성


function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms)
}
async function oneTick (ms) {
 console.log('start')
 await sleep(ms)
 console.log('end')
}
oneTick(3000)

잠자기 기능 설명

async PromiseFn() 함수가 실행되면 함수 실행이 일시 중지됩니다. 마이크로태스크. microTask가 실행되지 않으면 후속 MacroTask가 실행되지 않습니다. 또한 microTask의 이벤트 루프 기능을 통해 sleep 기능을 구현하여 console.log 실행을 방지합니다.

Process

1 콘솔 로그를 실행합니다. ('start')
2 wait를 실행하면 실행이 일시 중지되고 microTask에서 wait 함수가 실행된 후 PromiseFn을 기다립니다.
3 sleep 함수 내에서 반환까지 ms 지연
4 console.log('end' 실행 ) 반환 후 해결

nextTick API

vue에서 nextTick 사용 방법


vue.nextTick(() => {
 // todo...
})

용법을 이해한 후 소스코드를 살펴보세요


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]() // 逐个执行
  }
 }

 if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError) // 重点
  }
 } else if (&#39;!isIE MutationObserver&#39;) {
  var counter = 1
  var observer = new MutationObserver(nextTickHandler) // 重点
  var textNode = document.createTextNode(string(conter))

  observer.observe(textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
   textNode.data = String(counter)
  }
 } else {
  timerFunc = () => {
   setTimeout(nextTickHandler, 0) // 重点
  }
 }


 return function queueNextTick (cb, ctx) { // api的使用方式
  let _resolve
  callbacks.push(() => {
   if (cb) {
    try {
     cb.call(ctx)
    } catch (e) {
     err
    }
   } else if (_resolve) {
    _resolve(ctx)
   }
  })
  if (!pending) {
   pending = true
   timerFunc()
  }
  if (!cb && typeof Promise !== &#39;undefined&#39;) {
   return new Promise((resolve, reject) => {
    _resolve =resolve
   })
  }
 }
})() // 自执行函数

대강 살펴보기 소스 코드를 보면 nextTick api가 자체 실행 함수라는 것을 알 수 있습니다

이기 때문에 자체 실행 함수의 경우 반환 유형을 직접 보면 return function queueNextTick (cb, ctx) {...}


return function queueNextTick (cb, ctx) { // api的使用方式
  let _resolve
  callbacks.push(() => {
   if (cb) {
    try {
     cb.call(ctx)
    } catch (e) {
     err
    }
   } else if (_resolve) {
    _resolve(ctx)
   }
  })
  if (!pending) {
   pending = true
   timerFunc()
  }
  if (!cb && typeof Promise !== &#39;undefined&#39;) {
   return new Promise((resolve, reject) => {
    _resolve =resolve
   })
  }
 }

메인 프로세스 queueNextTick 함수가 우리에게 전달하는 ()에만 집중하세요 => { // todo ... } 콜백에 푸시됨


 if (typeof Promise !== &#39;undefined&#39; && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => { console.error(err) }
  timerFunc = () => {
   p.then(nextTickHandler).catch(logError) // 重点
  }
 } else if (&#39;!isIE MutationObserver&#39;) {
  var counter = 1
  var observer = new MutationObserver(nextTickHandler) // 重点
  var textNode = document.createTextNode(string(conter))

  observer.observe(textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
   textNode.data = String(counter)
  }
 } else {
  timerFunc = () => {
   setTimeout(nextTickHandler, 0) // 重点
  }
 }

이 섹션에서 표시된 세 가지 점을 볼 수 있습니다 Promise, MutationObserver 또는 setTimeout(fn, 0)이 다양한 브라우저 환경에서 nextTickHandler


를 실행하는 데 사용됨을 나타냅니다.

function nextTickHandler () {
  pending = false
  const copies = callbacks.slice(0) // 复制
  callbacks.length = 0 // 清空
  for (let i = 0; i < copies.length; i++) {
   copies[i]() // 逐个执行
  }
 }

nextTickHandler는 => { // todo... } 전에 콜백에 넣은 ()를 실행하는 것입니다. 현재 작업.

간단한 nextTick 작성

소스 코드가 복잡할 수 있습니다. 간단한 nextTick을 직접 작성해 보겠습니다.


const simpleNextTick = (function () {
 let callbacks = []
 let timerFunc

 return function queueNextTick (cb) {
  callbacks.push(() => { // 给callbacks 推入cb()
   cb()
  })

  timerFunc = () => {
   return Promise.resolve().then(() => {
    const fn = callbacks.shift()
    fn()
   })
  }
  timerFunc() // 执行timerFunc,返回到是一个Promise
 }
})()

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;)
})

여기서 nextTick의 원칙은 Promise를 반환하는 것이며 할 일 코드는 다음과 같습니다. Executeed in this Promise에서는 이제 계속해서


const simpleNextTick = (function () {
 return function queueNextTick (cb) {
  timerFunc = () => {
   return Promise.resolve().then(() => {
    cb()
   })
  }
  timerFunc()
 }
})()

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;)
})

을 단순화하고 이렇게 직접 작성할 수 있습니다.


const simpleNextTick = function queueNextTick (cb) {
  timerFunc = () => {
   return Promise.resolve().then(() => {
    cb()
   })
  }
  timerFunc()
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;)
})

이번에 자체 실행 기능도 단순화했습니다


const simpleNextTick = function queueNextTick (cb) {
   return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;)
})

이제 직접 끝까지 단순화해 보니 이제 nextTick의 핵심 내용이 마이크로 태스크인 Promise라는 것을 알 수 있습니다.

이제 vue의 nextTick API의 공식 예제로 돌아갑니다


<p id="example">{{message}}</p>
var vm = new Vue({
 el: &#39;#example&#39;,
 data: {
  message: &#39;123&#39;
 }
})
vm.message = &#39;new message&#39; // 更改数据
vm.$el.textContent === &#39;new message&#39; // false
Vue.nextTick(function () {
 vm.$el.textContent === &#39;new message&#39; // true
})

vue의 데이터가 업데이트된 후 dom 업데이트는 다음 이벤트 루프 이후에 실행된다는 것이 밝혀졌습니다.
nextTick을 사용하는 원리는 주로 단일 이벤트에서 데이터 업데이트 후 즉시 DOM을 운영하는 시나리오를 해결하는 것입니다.

이제 nextTick의 핵심이 microTask를 사용하는 것임을 알았으니 단순화된 nextTick과 처음에 절전 기능을 비교해 보겠습니다.


const simpleNextTick = function queueNextTick (cb) {
   return Promise.resolve().then(cb)
 }

simpleNextTick(() => {
 setTimeout(console.log, 3000, &#39;nextTick&#39;) // 也可以换成ajax请求
})


function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms) // 也可以换成ajax请求
}
async function oneTick (ms) {
 console.log(&#39;start&#39;)
 await sleep(ms)
 console.log(&#39;end&#39;)
}
oneTick(3000)

우리가 작성한 nextTick과 oneTick의 실행 결과가 너무나 유사하다는 것을 알 수 있습니다. 유일한 차이점은 nextTick이 Promise로 콜백을 래핑하고 이를 반환하고 실행하는 반면 oneTick은 Wait를 사용하여 Promise 함수를 실행하고 이 Promise에는 자체 래핑된 webapi 함수가 있다는 것입니다.

그러면 ajax 요청을 할 때 axios를 직접 사용하여 Promise 라이브러리를 반환할 수 있나요?


async function getData () {
  const data = await axios.get(url)
  // 操作data的数据来改变dom
  return data
}

이것도 nextTick과 같은 효과를 얻을 수 있습니다

마지막으로 탐색할 때 소스 코드에서 확인할 수 있는 것은 서버 환경이 Promise를 지원하지 않는 경우 MutationObserver 또는 setTimeout(cb, 0)을 사용하면 동일한 효과를 얻을 수 있습니다. 그러나 궁극적인 핵심은 microTask

관련 권장 사항:

Vue + Vuex에 대한 자세한 설명 vm.$nextTick 인스턴스 사용에 대한 자세한 설명

Vue의 nextTick 함수 소스 코드에 대한 자세한 설명

사용 예 Node.js의 process.nextTick

위 내용은 Vue.nextTick 구현 방법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.