Vue.nextTick 的实现方法详解

本文主要介绍了vue.nexttick 的实现方法,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮助到大家。

这是一篇继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  { 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   })  } }

登录后复制

只关注主流程queueNextTick函数把我们传入的() => { // todo… } 推入了callbacks内

 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) // 重点  } }

登录后复制

这一段我们可以看到标注的三个点表明在不同浏览器环境下使用Promise, MutationObserver或setTimeout(fn, 0) 来执行nextTickHandler

function nextTickHandler () {  pending = false  const copies = callbacks.slice(0) // 复制  callbacks.length = 0 // 清空  for (let i = 0; i 

nextTickHandler就是把我们之前放入callbacks的 () => { // todo... } 在当前tasks内执行。

写一个简单的nextTick

源码可能比较绕,我们自己写一段简单的nextTick


const simpleNextTick = (function () { let callbacks = [] let timerFunc return function queueNextTick (cb) {  callbacks.push(() => { // 给callbacks 推入cb()   cb()  })  timerFunc = () => {   return Promise.resolve().then(() => {    const fn = callbacks.shift()    fn()   })  }  timerFunc() // 执行timerFunc,返回到是一个Promise }})()simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick')})

登录后复制

我们可以从这里看出nextTick的原理就是返回出一个Promise,而我们todo的代码在这个Promise中执行,现在我们还可以继续简化

const simpleNextTick = (function () { return function queueNextTick (cb) {  timerFunc = () => {   return Promise.resolve().then(() => {    cb()   })  }  timerFunc() }})()simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick')})

登录后复制

直接写成这样。

const simpleNextTick = function queueNextTick (cb) {  timerFunc = () => {   return Promise.resolve().then(() => {    cb()   })  }  timerFunc() }simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick')})

登录后复制

这次我们把自执行函数也简化掉

const simpleNextTick = function queueNextTick (cb) {   return Promise.resolve().then(cb) }simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick')})

登录后复制

现在我们直接简化到最后,现在发现nextTick最核心的内容就是Promise,一个microtask。

现在我们回到vue的nextTick API官方示例

{{message}}

var vm = new Vue({ el: '#example', data: {  message: '123' }})vm.message = 'new message' // 更改数据vm.$el.textContent === 'new message' // falseVue.nextTick(function () { vm.$el.textContent === 'new message' // true})

登录后复制

原来在vue内数据的更新后dom更新是要在下一个事件循环后执行的。
nextTick的使用原则主要就是解决单一事件更新数据后立即操作dom的场景。

既然我们知道了nextTick核心是利用microTasks,那么我们把简化过的nextTick和开头的sleep函数对照一下。

const simpleNextTick = function queueNextTick (cb) {   return Promise.resolve().then(cb) }simpleNextTick(() => { setTimeout(console.log, 3000, 'nextTick') // 也可以换成ajax请求})

登录后复制

function sleep (ms) { return new Promise(resolve => setTimeout(resolve, ms) // 也可以换成ajax请求}async function oneTick (ms) { console.log('start') await sleep(ms) console.log('end')}oneTick(3000)

登录后复制

我们看出nextTick和我么写的oneTick的执行结果是那么的相似。区别只在于nextTick是把callback包裹一个Promise返回并执行,而oneTick是用await执行一个Promise函数,而这个Promise有自己包裹的webapi函数。

那在用ajax请求的时候我们是不是直接这样使用axios可以返回Promise的库

async function getData () {  const data = await axios.get(url)  // 操作data的数据来改变dom  return data}

登录后复制

这样也可以达到同nextTick同样的作用

最后我们也可以从源码中看出,当浏览器环境不支持Promise时可以使用MutationObserver或setTimeout(cb, 0) 来达到同样的效果。但最终的核心是microTask

相关推荐:

详解Vue + Vuex 使用 vm.$nextTick实例详解

Vue中nextTick函数源码详解

Node.js中的process.nextTick使用实例

以上就是Vue.nextTick 的实现方法详解的详细内容,更多请关注【创想鸟】其它相关文章!

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至253000106@qq.com举报,一经查实,本站将立刻删除。

发布者:PHP中文网,转转请注明出处:https://www.chuangxiangniao.com/p/2789916.html

(0)
上一篇 2025年3月8日 18:49:22
下一篇 2025年3月8日 09:55:18

AD推荐 黄金广告位招租... 更多推荐

相关推荐

  • Vue filter使用详解

    本文主要介绍了vue filter介绍及其使用详解,vuejs 提供了强大的过滤器api,能够对数据进行各种过滤处理。一起跟随小编过来看看吧,希望能帮助到大家。 VueJs 提供了强大的过滤器API,能够对数据进行各种过滤处理,返回需要的结…

    编程技术 2025年3月8日
    200
  • node nvm实现node多版本管理方法

    本文主要介绍了详解node nvm进行node多版本管理,希望能帮助大家更好的掌握ode多版本管理知识,一起来学习一下本文吧。 写在前面 nvm(nodejs version manager)是nodejs的管理工具,如果你需要快速更新no…

    2025年3月8日 编程技术
    200
  • bootstrap原理及优缺点详解

    本文主要和大家分享bootstrapbootstrap原理及优缺点,网格系统的实现原理,是通过定义容器大小,平分12份(也有平分成24份或32份,但12份是最常见的),再调整内外边距,最后结合媒体查询,就制作出了强大的响应式网格系统。boo…

    编程技术 2025年3月8日
    200
  • jquery手势密码插件详解

    手势密码也是现在很流行的一种功能本文主要介绍了jquery手势密码插件的相关知识,具有很好的参考价值,下面跟着小编一起来看下吧,希望能帮助到大家。 效果图: 代码如下: nbsp;html>   <!—->正确的密码是…

    2025年3月8日
    200
  • jquery PrintArea票据的套打功能实现方法

    套打就是指不打印表单上的表结构和固定的文言,只把会变化的数据打印出来,本文主要为大家带来一篇jquery printarea 实现票据的套打功能(代码)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧,希望能帮…

    2025年3月8日
    200
  • jQuery移动端Tab选项卡效果实现方法

    tab选项卡功能我们也会经常接触,本文我们主要介绍jquery实现移动端tab选项卡效果的实例。具有很好的参考价值。下面跟着小编一起来看下吧,希望能帮助到大家。 效果图: 代码如下: nbsp;html>   移动端Tab选项卡   …

    2025年3月8日
    200
  • jQuery中layer分页器实例详解

    本文主要介绍了jquery中layer分页器的使用,实例介绍了layer分页器的技巧,非常具有实用价值,需要的朋友可以参考下,希望能帮助到大家。 layui给我们提供了分页器的组件,进行简单的配置就能做出分页的效果 上代码: // 点击查询…

    编程技术 2025年3月8日
    200
  • jQuery字符串全部替换的实现方法

    大家对jquery字符串全部替换了解多少?本文主要介绍jquery实现字符串全部替换的方法,具有很好的参考价值。下面跟着小编一起来看下吧,希望能帮助到大家。 大家都是知道jquery有个replace方法可以将字符串中的”&#8…

    编程技术 2025年3月8日
    200
  • 超简单的瀑布流布局实现方法

    本文主要介绍了jquery实现超简单的瀑布流布局的实例,代码简单,容易修改。下面跟着小编一起来看下吧,希望能帮助到大家。 1.看看效果吧! 2.html代码index.html nbsp;html>  Title  ul{positi…

    2025年3月8日
    200
  • 关于jQuery插件zTree实现删除树节点方法详解

    本文主要介绍了jquery插件ztree实现删除树节点的方法,结合实例形式分析了jquery树插件ztree针对节点的遍历与删除操作相关技巧,需要的朋友可以参考下,希望能帮助到大家。 1、实现代码: nbsp;html>  zTree…

    2025年3月8日
    200

发表回复

登录后才能评论