이 글은 주로 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 !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // 重点 } } else if ('!isIE MutationObserver') { 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 !== 'undefined') { 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 !== 'undefined') { return new Promise((resolve, reject) => { _resolve =resolve }) } }
메인 프로세스 queueNextTick 함수가 우리에게 전달하는 ()에만 집중하세요 => { // todo ... } 콜백에 푸시됨
if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve() var logError = err => { console.error(err) } timerFunc = () => { p.then(nextTickHandler).catch(logError) // 重点 } } else if ('!isIE MutationObserver') { 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, 'nextTick') })
여기서 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, 'nextTick') })
을 단순화하고 이렇게 직접 작성할 수 있습니다.
const simpleNextTick = function queueNextTick (cb) { timerFunc = () => { return Promise.resolve().then(() => { cb() }) } timerFunc() } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
이번에 자체 실행 기능도 단순화했습니다
const simpleNextTick = function queueNextTick (cb) { return Promise.resolve().then(cb) } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') })
이제 직접 끝까지 단순화해 보니 이제 nextTick의 핵심 내용이 마이크로 태스크인 Promise라는 것을 알 수 있습니다.
이제 vue의 nextTick API의 공식 예제로 돌아갑니다
<p id="example">{{message}}</p> var vm = new Vue({ el: '#example', data: { message: '123' } }) vm.message = 'new message' // 更改数据 vm.$el.textContent === 'new message' // false Vue.nextTick(function () { vm.$el.textContent === 'new message' // true })
vue의 데이터가 업데이트된 후 dom 업데이트는 다음 이벤트 루프 이후에 실행된다는 것이 밝혀졌습니다.
nextTick을 사용하는 원리는 주로 단일 이벤트에서 데이터 업데이트 후 즉시 DOM을 운영하는 시나리오를 해결하는 것입니다.
이제 nextTick의 핵심이 microTask를 사용하는 것임을 알았으니 단순화된 nextTick과 처음에 절전 기능을 비교해 보겠습니다.
const simpleNextTick = function queueNextTick (cb) { return Promise.resolve().then(cb) } simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') // 也可以换成ajax请求 })
function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) // 也可以换成ajax请求 } async function oneTick (ms) { console.log('start') await sleep(ms) console.log('end') } 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
관련 권장 사항:
Node.js의 process.nextTick 사용 예
node.js_node.js의 타이머 nextTick() 및 setImmediate() 차이점 분석
의 process.nextTick 사용 예위 내용은 Vue.nextTick 구현 방법에 대한 간략한 분석의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!