이 글에서는 주로 Vuejs의 nextTick() 비동기 업데이트 큐에 대한 소스 코드 분석을 소개합니다. 이제 이를 공유하고 참고 자료를 제공하겠습니다.
Vue 공식 웹사이트는 이를 다음과 같이 설명합니다.
Vue2.0의 비동기 업데이트 큐에 대한 심층적인 반응 원리
공식 웹사이트는 다음과 같이 설명합니다.
데이터 변경 사항이 관찰되는 한 Vue는 큐를 열고 버퍼링합니다. same event 루프 내에서 발생하는 모든 데이터 변경 사항입니다. 동일한 감시자가 여러 번 트리거되면 대기열에 한 번만 푸시됩니다. 버퍼링 중 이러한 중복 제거는 불필요한 계산 및 DOM 작업을 방지하는 데 중요합니다. 그런 다음 다음 이벤트 루프 "틱"에서 Vue는 큐를 플러시하고 실제(중복 제거된) 작업을 수행합니다. Vue는 내부적으로 비동기 대기열에 기본 Promise.then 및 MutationObserver를 사용하려고 시도합니다. 실행 환경이 이를 지원하지 않으면 대신 setTimeout(fn, 0)이 사용됩니다.
예를 들어 vm.someData = 'new value' 로 설정하면 구성 요소가 즉시 다시 렌더링되지 않습니다. 대기열이 플러시되면 이벤트 루프 대기열이 지워지는 다음 "틱"에서 구성 요소가 업데이트됩니다. 대부분의 경우 이 프로세스에 대해 걱정할 필요가 없지만 DOM 상태가 업데이트된 후에 뭔가를 하려는 경우 약간 까다로울 수 있습니다. Vue.js는 일반적으로 개발자가 "데이터 기반" 방식으로 생각하고 DOM을 직접 건드리지 않도록 권장하지만 실제로 그렇게 해야 할 때가 있습니다. 데이터 변경 후 Vue가 DOM 업데이트를 완료할 때까지 기다리려면 데이터 변경 직후 Vue.nextTick(콜백)을 사용할 수 있습니다. 이 콜백 함수는 DOM 업데이트가 완료된 후에 호출됩니다. 예를 들어
소스 코드 분석
메소드 프로토타입과 파싱 코멘트는 다음과 같습니다.
var nextTick = (function () { var callbacks = []; // 存储需要触发的回调函数 var pending = false; // 是否正在等待的标识(false:允许触发在下次事件循环触发callbacks中的回调, true: 已经触发过,需要等到下次事件循环) var timerFunc; // 设置在下次事件循环触发callbacks的 触发函数 //处理callbacks的函数 function nextTickHandler () { pending = false;// 可以触发timeFunc var copies = callbacks.slice(0);//复制callback callbacks.length = 0;//清空callback for (var i = 0; i < copies.length; i++) { copies[i]();//触发callback回调函数 } } //如果支持Promise,使用Promise实现 if (typeof Promise !== 'undefined' && isNative(Promise)) { var p = Promise.resolve(); var logError = function (err) { console.error(err); }; timerFunc = function () { p.then(nextTickHandler).catch(logError); // ios的webview下,需要强制刷新队列,执行上面的回调函数 if (isIOS) { setTimeout(noop); } }; //如果Promise不支持,但是支持MutationObserver(h5新特性,异步,当dom变动是触发,注意是所有的dom都改变结束后触发) } else if (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 IE11, iOS7, Android 4.4 var counter = 1; var observer = new MutationObserver(nextTickHandler); //创建一个textnode dom节点,并让MutationObserver 监视这个节点;而 timeFunc正是改变这个dom节点的触发函数 var textNode = document.createTextNode(String(counter)); observer.observe(textNode, { characterData: true }); timerFunc = function () { counter = (counter + 1) % 2; textNode.data = String(counter); }; } else {// 上面两种不支持的话,就使用setTimeout timerFunc = function () { setTimeout(nextTickHandler, 0); }; } //nextTick接受的函数, 参数1:回调函数 参数2:回调函数的执行上下文 return function queueNextTick (cb, ctx) { var _resolve;//用于接受触发 promise.then中回调的函数 //向回调数据中pushcallback callbacks.push(function () { //如果有回调函数,执行回调函数 if (cb) { cb.call(ctx); } if (_resolve) { _resolve(ctx); }//触发promise的then回调 }); if (!pending) {//是否执行刷新callback队列 pending = true; timerFunc(); } //如果没有传递回调函数,并且当前浏览器支持promise,使用promise实现 if (!cb && typeof Promise !== 'undefined') { return new Promise(function (resolve) { _resolve = resolve; }) } } })();
코멘트에서 nextTick() 함수의 로직을 설명했습니다.
위의 세 가지 콜백 처리 방식을 사용하는 이유 우선 순위: Promise와 MutationObserver 및 트리거된 이벤트는 동일한 이벤트 루프에 있지만(그러나 마이크로 큐에서 실행됨) setTimeout의 콜백 함수는 다음 시간 루프에서 실행되기 때문입니다.
Promise를 먼저 사용하는 이유는 MutationObserver가 ios9.3.3 이상의 UIWebview에서 일정시간 실행 후 멈추기 때문입니다.
위 코드의 주석은 코드 논리를 완전히 설명했습니다. 간단한 이해: 콜백이 아직 실행되지 않은 경우 콜백 함수는 다음 이벤트 루프 실행 중에 트리거됩니다.
참고: 콜백 함수를 설정하지 않고 nextTick()을 사용하지만 Promise를 사용하여 콜백 함수를 설정하면 이는 현재 Vue 인스턴스가 아니라 창을 가리킵니다(엄격 모드는 정의되지 않음). 위 분석에서는 실행 컨텍스트가 Promise.then()에 있는 콜백 함수의 첫 번째 매개변수를 통해 전달되는 것을 보여줍니다.
nextTick()을 사용합니다.
1. 글로벌 Vue의 기능이므로 vue를 통해 직접 호출할 수 있습니다. 2. Vue 시스템에서는 DOM 업데이트 작업을 처리하는 데 사용됩니다. Vue에는 데이터 변경을 관찰한 다음 DOM을 업데이트하는 데 사용되는 감시자가 있습니다. 우리는 Vue에서 모든 데이터 변경이 DOM 업데이트를 트리거하는 것은 아니라는 것을 알고 있었습니다. 대신 이러한 작업은 큐에 캐시됩니다. 이벤트 루프가 끝나면 큐가 새로 고쳐지고 dom 업데이트 작업이 균일하게 수행됩니다.function queueWatcher (watcher) { var id = watcher.id; if (has[id] == null) { has[id] = true; if (!flushing) { queue.push(watcher); } else { // if already flushing, splice the watcher based on its id // if already past its id, it will be run next immediately. var i = queue.length - 1; while (i >= 0 && queue[i].id > watcher.id) { i--; } queue.splice(Math.max(i, index) + 1, 0, watcher); } // queue the flush if (!waiting) { waiting = true; nextTick(flushSchedulerQueue); } } }위 코드는 watcher에서 나온 코드이고 나중에 분석할 예정이므로 논리를 간략하게 설명하세요. 여기서 nextTick()의 기능은 이 이벤트 루프의 끝에서 감시자가 확인한 dom 업데이트 작업을 새로 고치는 것입니다. 3. Partial Vue는 $nextTick()을 트리거하고 dom이 업데이트된 후 해당 로직을 실행합니다.
Vue.prototype.$nextTick = function (fn) { return nextTick(fn, this)// 设置nextTick回调函数的上下文环境是当前Vue实例 };위는 렌더 모듈을 초기화하는 코드인 renderMinxin의 코드입니다.
요약
코드를 이해하지 못하면 오해를 하게 됩니다. 1.nextTick()은 현재 페이지를 다시 그리지 않으며 페이지가 다시 그려질 때까지 실행되지 않지만 이벤트 루프가 끝난 후에는 확실히 실행됩니다. 2. 첫 번째 항목은 이미 언급한 바 있지만 이 메서드에서 업데이트된 데이터를 얻을 수 있는 이유는 dom 요소의 속성이 이미 완료되어 있기 때문입니다. 와처에서 플러시되었습니다. 큐가 변경되었으므로 지금 얻을 수 있습니다.위 사항을 증명하는 예:
h5에는 requestFrameAnimation(콜백) 메서드가 있습니다. 이 메서드의 콜백은 페이지를 다시 그리기 전에 호출됩니다. 실험을 통해 dom을 업데이트할 때 이 메서드보다 먼저 nextTick()이 실행됩니다. 위 내용은 제가 여러분을 위해 정리한 내용입니다. 앞으로 도움이 되길 바랍니다. 관련 기사:Bootstrap 프레임워크에서 treeview를 사용하여 데이터를 동적으로 로드하는 방법
위 내용은 Vuejs에서 nextTick()을 통해 비동기 업데이트 큐 구현의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!