Vue source code learning nextTick

Preface

Recently, I am studying the Vue source code of teacher ustbhuangyi to analyze the course in an all-round way. The following content can be regarded as class notes.

 

JS operating mechanism

In order to facilitate the understanding of nextTick, you need to understand the operating mechanism of JS first.

Reference link:

https://ustbhuangyi.github.io/vue-analysis/v2/reactive/next-tick.html#js-%E8%BF%90%E8%A1%8C%E6%9C%BA%E5%88%B6

JS execution is single-threaded, and it is based on an event loop. The event loop is roughly divided into the following steps:

(1) All synchronization tasks are executed on the main thread, forming an execution context stack.

(2) In addition to the main thread, there is also a "task queue". As long as the asynchronous task has a running result, an event is placed in the "task queue".

(3) Once all synchronization tasks in the "execution stack" are executed, the system will read the "task queue" to see what events are in it. Those corresponding asynchronous tasks then end the waiting state, enter the execution stack, and begin execution.

(4) The main thread keeps repeating the third step above.

 

My understanding

Simple test

<script>
  console.log(1)
  console.log(2)
  console.log(3)
  console.log(4)
  test()
  console.log(5)
  console.log(6)
  console.log(7)
  console.log(8)

  function test(){
    console.log("a")
    setTimeout(function(){console.log("b")},1000)
  }
</script>

 Print order

 

Source code implementation

The essence of nextTick source code implementation is to collect the functions to be implemented, collect them in the callbacks array, and then traverse the array in the next tick to execute the callback.

src/core/util/next-tick.js

const callbacks = []

......

export function nextTick (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 ()

}

// $flow-disable-line

if (!cb && typeof Promise !== 'undefined') {

return new Promise(resolve => {

_resolve = resolve

})

}

}

 

test

<template>

<div class="hello">

<h1 ref="msg">{ { msg }}</h1>

<div>

<button @click="changeText1">change1</button>

<button @click="changeText2">change2</button>

</div>

</div>

</template>

 

<script>

export default {

name: 'NextTick',

data () {

return {

msg: 'hello world'

}

},

methods: {

changeText1 () {

this.msg = 'hello vue'

// Synchronously output dom results

console.log('sync: msg = ' + this.$refs.msg.innerText)// 输出hello world

// Asynchronously output dom results

// The following two ways can be written

// this.$nextTick(()=>{

// console.log("nextTick: msg = "+this.$refs.msg.innerText)

// })

this.$nextTick().then(() => {

console.log('nextTick: msg = ' + this.$refs.msg.innerText)// 输出hello vue

})

},

changeText2 () {

// The execution order is related to the writing order

this.$nextTick(() => {

console.log('nextTick: msg = ' + this.$refs.msg.innerText)// 输出hello world

})

this.msg = 'hello vue'

// Synchronously output dom results

console.log('sync: msg = ' + this.$refs.msg.innerText)// 输出hello world

// Asynchronously output dom results

// Conclusion: The change of data to the re-rendering of dom is an asynchronous process

this.$nextTick().then(() => {

console.log('nextTick: msg = ' + this.$refs.msg.innerText)// 输出hello vue

})

}

}

}

</script>

 

to sum up

The data change to the re-rendering of the DOM is an asynchronous process, which occurs in the next tick.

This is what we usually do in the development process, such as when we get data from the server interface, the data is modified. If some of our methods rely on the DOM changes after the data modification, we must execute it after nextTick.

For example, the following pseudo code:

getData(res).then(()=>{

  this.xxx = res.data

  this.$nextTick(() => {

    // Here we can get the changed DOM

  })

})

The update of the rendering watcher is triggered after the data is changed, but the flush of the watchers is after nextTick, so the re-rendering is asynchronous.

 

 

 

Guess you like

Origin blog.csdn.net/Irene1991/article/details/114097688