首页 > 语言 > JavaScript > 正文

浅谈Vue.nextTick 的实现方法

2024-05-06 15:25:15
字体:
来源:转载
供稿:网友

这是一篇继event loop和MicroTask 后的vue.nextTick API实现的源码解析。

预热,写一个sleep函数

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)

解释下sleep函数

async 函数进行await PromiseFn()时函数执行是暂停的,我们也知道现在这个PromiseFn是在microTask内执行。当microTask没执行完毕时,后面的macroTask是不会执行的,我们也就通过microTask在event loop的特性实现了一个sleep函数,阻止了console.log的执行

流程

1执行console.log('start')
2执行await 执行暂停,等待await函数后的PromiseFn在microTask执行完毕
3在sleep函数内,延迟ms返回
4返回resolve后执行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类型,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   })  } }            
发表评论 共有条评论
用户名: 密码:
验证码: 匿名发表

图片精选