SoFunction
Updated on 2025-04-04

Brief discussion on the implementation method

This is a source code analysis of the API implementation after event loop and MicroTask.

Preheat, write a sleep function

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

Explain the sleep function

The function execution is paused when the async function performs await PromiseFn(), and we also know that the PromiseFn is now executed in microTask. When the microTask is not executed, the subsequent macroTask will not be executed. We also implement a sleep function in the event loop feature through the microTask, which prevents execution.

process

1Execute('start')
2Execute await Execute pause, wait for the PromiseFn after the await function to be executed in microTask
3 In the sleep function, delay ms return
4. After returning resolve, execute ('end')

nextTick API

How to use nextTick in vue

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

After understanding the usage, look at the source code

const nextTick = (function () {
 const callbacks = []
 let pending = false
 let timerFunc // Timed function
 function nextTickHandler () {
  pending = false
  const copies = (0) // copy   = 0 // Clear  for (let i = 0; i < ; i++) {
   copies[i]() // Execute one by one  }
 }

 if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = ()
  var logError = err => { (err) }
  timerFunc = () => {
   (nextTickHandler).catch(logError) // Focus  }
 } else if ('!isIE MutationObserver') {
  var counter = 1
  var observer = new MutationObserver(nextTickHandler) // Focus  var textNode = (string(conter))

  (textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
    = String(counter)
  }
 } else {
  timerFunc = () => {
   setTimeout(nextTickHandler, 0) // Focus  }
 }


 return function queueNextTick (cb, ctx) { //How to use API  let _resolve
  (() => {
   if (cb) {
    try {
     (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
   })
  }
 }
})() // Self-execution function

A rough look at the source code can help you understand that nextTick api is a self-executing function

Since it is a self-executing function, look directly at its return type. return function queueNextTick (cb, ctx) {...}

return function queueNextTick (cb, ctx) { //How to use API  let _resolve
  (() => {
   if (cb) {
    try {
     (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
   })
  }
 }

Only focus on the main process queueNextTick function pushes the() => { // todo... } we passed into callbacks

 if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = ()
  var logError = err => { (err) }
  timerFunc = () => {
   (nextTickHandler).catch(logError) // Focus  }
 } else if ('!isIE MutationObserver') {
  var counter = 1
  var observer = new MutationObserver(nextTickHandler) // Focus  var textNode = (string(conter))

  (textNode, {
   characterData: true
  })
  timerFunc = () => {
   counter = (counter + 1) % 2
    = String(counter)
  }
 } else {
  timerFunc = () => {
   setTimeout(nextTickHandler, 0) // Focus  }
 }

In this paragraph, we can see the three points marked indicating that Promise, MutationObserver or setTimeout(fn, 0) is used to execute nextTickHandler in different browser environments.

function nextTickHandler () {
  pending = false
  const copies = (0) // copy   = 0 // Clear  for (let i = 0; i < ; i++) {
   copies[i]() // Execute one by one  }
 }

nextTickHandler is to execute the () => { // todo... } that we put in callbacks before and execute in the current tasks.

Write a simple nextTick

The source code may be quite confusing, so let's write a simple nextTick ourselves

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

 return function queueNextTick (cb) {
  (() => { // Push cb() to callbacks   cb()
  })

  timerFunc = () => {
   return ().then(() => {
    const fn = ()
    fn()
   })
  }
  timerFunc() // Execute timerFunc, return to a Promise }
})()

simpleNextTick(() => {
 setTimeout(, 3000, 'nextTick')
})

We can see from here that the principle of nextTick is to return a promise, and our todo code is executed in this promise, and now we can continue to simplify it

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

simpleNextTick(() => {
 setTimeout(, 3000, 'nextTick')
})

Write it directly like this.

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

simpleNextTick(() => {
 setTimeout(, 3000, 'nextTick')
})

This time we simplify the self-executing function

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

simpleNextTick(() => {
 setTimeout(, 3000, 'nextTick')
})

Now we simplify it directly to the end, and now we find that the core content of nextTick is Promise, a microtask.

Now let's go back to vue's nextTick API official example

<div >{{message}}</div>
var vm = new Vue({
 el: '#example',
 data: {
  message: '123'
 }
})
 = 'new message' // Change the datavm.$ === 'new message' // false
(function () {
 vm.$ === 'new message' // true
})

It turns out that after the data in vue is updated, the dom update is to be executed after the next event loop.
The principle of nextTick is mainly to solve the scenario where the dom is operated immediately after a single event is updated.

Since we know that nextTick core is to use microTasks, then we compare the simplified nextTick with the beginning sleep function.

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

simpleNextTick(() => {
 setTimeout(, 3000, 'nextTick') // It can also be replaced with ajax request})
function sleep (ms) {
 return new Promise(resolve => setTimeout(resolve, ms) // It can also be replaced with ajax request}
async function oneTick (ms) {
 ('start')
 await sleep(ms)
 ('end')
}
oneTick(3000)

We can see that the execution results of nextTick and oneTick written by me are so similar. The only difference is that nextTick wraps a callback and returns and executes it, while oneTick uses await to execute a Promise function, and this Promise has its own wrapped webapi function.

When using ajax request, do we use axios directly to return the library that can return the Promise

async function getData () {
  const data = await (url)
  // Operate data to change the dom  return data
}

This can also achieve the same effect as nextTick

Finally, we can also see from the source code that when the browser environment does not support Promise, you can use MutationObserver or setTimeout(cb, 0) to achieve the same effect. But the ultimate core is microTask

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.