>웹 프론트엔드 >View.js >이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

青灯夜游
青灯夜游앞으로
2022-12-21 20:43:101980검색

이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

2023년이 거의 다 됐는데 아직도 모르시나요?$nextTick? Vue2가 나온 지 거의 10년이 됐고, Vue3도 나온 지 2년이 넘었어요. 그렇죠! 말하기 부끄럽네요. 지금은 this.nextTick만 알고 있습니다. (사실을 말하자면) 자 일단 바이두에서 검색해 볼까요 클릭 클릭 클릭... 재빠르게 Vue.js 공식 홈페이지 문서로 뛰어가서 갑자기 발견한 내용은 다음과 같습니다. :

nextTick: 다음 DOM 업데이트 루프가 끝난 후 지연된 콜백을 실행합니다. 업데이트된 DOM을 얻으려면 데이터를 수정한 후 즉시 이 방법을 사용하세요. 여기에는 두 개의 매개변수가 있습니다. 첫 번째 매개변수는 전달되지 않은 경우 약속 호출을 제공하는 콜백 함수이고, 두 번째 매개변수는 전달되지 않으면 자동 바인딩으로 기본 설정되는 실행 환경 컨텍스트입니다. . 은 이를 호출하는 인스턴스에 할당됩니다. [관련 권장사항: vuejs 비디오 튜토리얼, 웹 프론트엔드 개발]回调函数,不传时提供promise调用;第二个参数是执行环境上下文,不传默认是自动绑定到调用它的实例上。【相关推荐:vuejs视频教程web前端开发

我们先看看nextTick究竟是个啥?

console.log(this.$nextTick);
// 控制台打印
if(fn){
  return nextTick(fn, this);
}

我们可以看出nextTick就是一个方法,方法有两个参数:fn和this,fn就是需要传的回调函数,this就是所说的执行环境上下文。那么问题来了,在Vue中是如何实现在下一次DOM更新结束之后才会执行延迟回调的? 我们先看看下面的例子:

<div ref="test1">created:{{message}}</div>
// vue实例
data: {
    message: "Hello World!",
},
created(){
    this.message = &#39;你好,世界!&#39;;
    console.log(this.$refs.test1.innerText);// 报错
    // TypeError: Cannot read properties of undefined (reading &#39;innerText&#39;)
    this.$nextTick(()=>{
         console.log(&#39;test1 nextTick:&#39;,this.$refs.test1.innerText);// 你好,世界!
    });
},

从上面例子中,在created生命周期中操作了DOM,但是我们都知道created生命周期只是初始化了数据,这期间是还没有渲染DOM的,如果我们直接操作DOM是找不到DOM元素的,那么问题来了:为什么放在nextTick中就可以获取到了DOM元素呢? 这不是很明显吗,等到DOM渲染完才调用不就获取到了吗,从而知道了nextTick作用就是用来等下次DOM渲染完才去调用nextTick内的DOM操作代码

먼저 무엇인지 살펴보겠습니다. 넥스트틱은?

console.log(&#39;同步代码1&#39;);
setTimeout(function () {
    console.log("setTimeout");
}, 0);
new Promise((resolve) => {
    console.log(&#39;同步代码2&#39;)
    resolve()
}).then(() => {
    console.log(&#39;promise.then&#39;)
})
console.log(&#39;同步代码3&#39;);
nextTick이 메소드라는 것을 알 수 있습니다. 이 메소드에는 fn과 this라는 두 가지 매개변수가 있습니다. fn

은 전달되어야 하는 콜백 함수입니다.

this는 소위 실행 환경 컨텍스트입니다. 그래서 질문은 다음 DOM 업데이트가 완료될 때까지 Vue에서 지연된 콜백을 구현하는 방법은 무엇입니까? 먼저 다음 예시를 살펴보겠습니다.

// 同步代码1
// 同步代码2
// 同步代码3
// promise.then 
// setTimeout
위 예시에서 생성된 라이프 사이클에서 DOM이 조작되지만, 생성된 라이프 사이클은 데이터 초기화만 할 뿐 DOM은 렌더링되지 않는다는 사실을 우리 모두 알고 있습니다. 이 기간 동안 DOM을 운영할 때 DOM 요소를 직접 찾을 수 없으면 다음과 같은 질문이 발생합니다. DOM 요소를 nextTick에 배치하여 얻을 수 있는 이유는 무엇입니까?

DOM이 렌더링될 때까지 기다렸다가 호출하면 얻을 수 있습니다. 그렇다면 nextTick의 기능은 DOM 작업을 호출하기 전에 다음 번 DOM이 렌더링될 때까지 기다리는 것이라는 것을 알 수 있습니다. nextTick의 코드입니다. 그러면 질문이 다시 제기됩니다. nextTick은 정확히 무엇을 합니까? Vue2, Vue3 버전의 nextTick 원리를 소스코드 레벨에서 분석해 보겠습니다.

이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

nextTick의 Vue2 버전
  • Vue는 개발자에게 nextTick 메서드를 노출하므로 이 메서드에서는 세 가지 주요 작업이 수행됩니다.
콜백 함수 추가

, 이에 대해 더 깊이 이해해 보겠습니다.$nextTick!콜백 함수의 지연된 실행

,
    현재 여부 판단 nextTick은 콜백 함수
  • 에 전달됩니다. 전달되지 않으면 Promise, this.$nextTick.then(()=>{})이며 Promise로 처리됩니다.
  • 현재 범위에 여러 nextTick 함수가 있을 수 있으므로 콜백 함수가 콜백 배열에 추가됩니다.

이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

🎜 현재 nextTick이 Pending=true로 표시되었는지, 즉 실행 중인지 확인합니다. 그렇지 않은 경우에는 TimerFunc를 실행합니다(🎜비동기 실행 함수는 flashCallbacks 함수 호출을 비동기적으로 지연하는 데 사용됩니다🎜). timeFunc의 실행은 현재 환경이 Promise, MutationObserver, setImmediate 및 setTimeout을 지원하는지 여부를 결정합니다. 우선순위는 앞에서 뒤로이며 4가지 상황으로 나뉩니다. 🎜🎜🎜🎜Promise가 먼저 사용됩니다. 현재 환경이 Promise를 지원하면 nextTick이 사용됩니다. 지연된 콜백 함수를 실행하기 위해 타이머Func는 es6 이하의 구문인 Promise를 실행합니다. 현재 환경이 es6 이하의 구문만 지원한다면 이후 지원만 고려할 수 있습니다. 🎜🎜🎜🎜🎜
  • 支持MutationObserver,HTML5的api,中文意思是:修改的监听,MutationObserver用来监听DOM的变动,比如节点的增减、属性的变动、文本内容的修改等都会触发MutationObserver事件。注意地,与事件不同,事件是同步触发,DOM的变动会立即触发事件,而MutationObserver事件是异步触发,DOM不会立即触发,需要等当前所有DOM操作完毕才会触发。

MutationObserver有7个属性:childList(true,监听子节点的变动)、attributes(true,监听属性的变动)、characterData(true,监听节点内容或节点文本的变动)、subtree(是否应用于该节点的所有后代节点)、attributeOldValue(观察attributes变动时,是否需要记录变动前的属性值)、characterDataOldValue(观察characterData变动时,是否需要记录变动前的值)、attributeFilter(数组,表示需要观察的特定属性(比如[‘class’,‘src’])。

为什么需要创建一个文本节点?因为在这里操作DOM保证浏览器页面是最新DOM渲染的,虽然看来好像是没什么作用,但这是保证拿到的DOM是最新的。

이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

  • 支持setImmediatesetTimeout,setImmediate即时计时器立即执行工作,它是在事件轮询之后执行,为了防止轮询阻塞,每次只会调用一个。setTimeout按照一定时间后执行回调函数。

이에 대해 더 깊이 이해해 보겠습니다.$nextTick!

好了好了,到了现在,我们都知道nextTick做了什么吧,但是我们有没有想过这样的一个问题:既然都是异步回调执行等待DOM更新后才去调用操作DOM的代码,那么这个机制又是什么原理?这就是JS的执行机制有关了,涉及宏任务与微任务的知识,我们先来看看这样的一道题:

console.log(&#39;同步代码1&#39;);
setTimeout(function () {
    console.log("setTimeout");
}, 0);
new Promise((resolve) => {
    console.log(&#39;同步代码2&#39;)
    resolve()
}).then(() => {
    console.log(&#39;promise.then&#39;)
})
console.log(&#39;同步代码3&#39;);

我们可能会问上面的输出是个啥,首先js是单线程,所以在js程序运行中只有一个执行栈,实现不了多线程,所以就需要任务均衡分配,通俗的讲,按任务急优先处理原则,js中分为同步任务和异步任务,异步任务又分为宏任务和微任务,同步任务先入栈,程序会先把执行栈中的所有同步任务执行完,再去判断是否有异步任务,而异步任务中微任务的优先级高于宏任务。如果当前执行栈为空,而微任务队列不为空,就先执行微任务,等把所有微任务执行完,最后才会考虑宏任务。而上面代码中Promise是属于微任务,而setTimeout是宏任务,所以上面的输出为:

// 同步代码1
// 同步代码2
// 同步代码3
// promise.then 
// setTimeout

使用Vue2的nextTick

  • 传入回调函数参数使用:

    this.$nextTick(()=>{
      // ...操作DOM的代码
    })
  • 不传入回调函数参数使用:

    // 方式一
    this.$nextTick().then(()=>{
      // ...操作DOM的代码
    })
    
    // 方式二
    await this.$nextTick();
    // 后写操作DOM的代码

Vue3版本的nextTick

Vue3版本就没有Vue2版本的那么多环境支持,nextTick封装成了一个Promise异步回调函数执行。

// Vue3.2.45
// core-main\core-main\packages\runtime-core\src
export function nextTick<T = void>(
  this: T,
  fn?: (this: T) => void
): Promise<void> {
  const p = currentFlushPromise || resolvedPromise
  return fn ? p.then(this ? fn.bind(this) : fn) : p
}

使用Vue3的nextTick

  • 传入回调函数使用

    import { nextTick } from &#39;vue&#39; // 引入
    setup () {    
    nextTick(()=>{
       // ...操作DOM的代码
    })
  • 不传入回调函数的使用

    import { nextTick } from &#39;vue&#39; // 引入
    setup () {    
        // 方式一
        nextTick().then(()=>{
          // ...操作DOM的代码
        })
    
        // 方式二
        await nextTick();
        // 后写操作DOM的代码
    }

总结

  • nextTick可以通俗的当作一个Promise,所以nextTick属于微任务。
  • nextTick在页面更新数据后,DOM更新,可以通俗理解为,nextTick就是用来支持操作DOM的代码及时更新渲染页面。也就是在数据变化后要执行的某个操作,而这个操作需要使用随数据改变而改变的DOM结构的时候,这个操作都应该放进Vue.nextTick()的回调函数中。
  • 在Vue生命周期的created()钩子函数进行的DOM操作一定要放在Vue.nextTick()的回调函数中。

(学习视频分享:vuejs入门教程编程基础视频

위 내용은 이에 대해 더 깊이 이해해 보겠습니다.$nextTick!의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 juejin.cn에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제