乐趣区

关于前端:思考nextTick-与-setTimeout-的一点对比

作者:Chimezie Enyinnaya
译者:前端小智
起源:blog

有幻想,有干货,微信搜寻 【大迁世界】 关注这个在凌晨还在刷碗的刷碗智。

本文 GitHub https://github.com/qq449245884/xiaozhi 已收录,有一线大厂面试残缺考点、材料以及我的系列文章。

一个前端开发人员 (小智) 走进了一个 Vue 酒吧。小智点了他最喜爱的鸡尾酒:Nuxt。酒保正在致力制作中。而后他本人就唠叨了起来。

小智讲述了他是如何在 Vue 3 的实例办法下发现 $nextTick 的,并大吃一惊。小智
应用 Vue 曾经有一段时间了,他曾经习惯了把 $watch$emit写成实例办法。那么,$nextTick 是用来做什么的?Vue 文档说,它 ”[defers]回调,在下一个 DOM 更新周期后执行 ”。

然而小智并不置信。

他持续讲述他是如何尝试这样做的:

this.loadingAnimation = true
this.startVeryLongCalculation()
this.completeVeryLongCalculation()
this.loadingAnimation = false

有用。为什么?

nextTick 做什么?

nextTick承受一个提早到下一个 DOM 更新周期的回调函数。这只是 Vue 的一种说法,” 嘿,如果你想在 DOM 更新后执行一个函数(这种状况很少产生),我心愿你应用 nextTick 而不是setTimeout“。

Vue.nextTick(() => {}) // syntax

上面很快就会讲到 setTimeoutnextTick参数。咱们用这个例子来可视化 nextTick 的行为:

<template>
  <div>
    {{currentTime}}
  </div>
</template>

<script>
export default {
  name: 'getCurrentTime',
  data() {
    return {currentTime: ''}
  },
  mounted() {
    this.currentTime = 3;

    this.$nextTick(() => {let date = new Date()
        this.currentTime = date.getFullYear()});
  }
}
</script>

在 J 电脑上运行这个代码片段。它将显示 2021 年。并不是说如果你去掉nextTick,就不会失去同样的后果。然而,你应该明确,Vue 会依据数据中的内容对 DOM 进行批改。

在下面的代码片段中,Vue 将 DOM 更新为3,而后调用回调,将 DOM 更新为2021,最初将控制权交给浏览器,浏览器将显示2021

到目前为止,咱们曾经钻研了 nextTick 在回调队列中插入回调函数并在适当的时候执行该函数。

这个你可能会感兴趣,nextTick中的回调是作为事件循环中的一个微工作应用的。nextTick的源代码明确指出,”nextTick行为利用了微工作队列,能够通过本地的 Promise.thenMutationObserver来拜访。”

setTimeout vs nextTick

在 DOM 更新后执行函数的另一种办法是应用 JavaScript 的 setTimeout() 函数。

咱们将下面的代码用 setTimeout 替换nextTick:

<template>
  <div>
    {{currentTime}}
  </div>
</template>

<script>
export default {
  name: 'getCurrentTime',
  data() {
    return {currentTime: ''}
  },
  mounted() {
    this.currentTime = 3;

    setTimeout(() => {let date = new Date()
      this.currentTime = date.getFullYear()}, 0);
  }
}
</script>

运行此代码片段。首先看到 3 而后2021。它产生得很快,因而如果没有看到此行为,须要刷新浏览器。

在下面的代码片段中,Vue 将 DOM 更新为3,并提供浏览器管制。而后浏览器显示3,调用回调函数,将 DOM 更新到2021,最初将控制权交给浏览器,当初浏览器显示2021

nextTick的实现在不反对 PromiseMutationObserver的浏览器(IE 6-10 和 Opera Mini 浏览器)上,应用 s etTimeout作为后备办法,对于不反对 PromiseMutationObserver的浏览器(IE 10),它更偏向于setImmediate

何时应用 nexttick

  • 当你想应用 setTimeout
  • 当你想确定 DOM 能反映你的数据时
  • 在尝试执行异步操作时,遇到 Uncaught (in promise) DOMException 等谬误。记住,Vue 是异步更新 DOM 的

最初来个示例:

<div id="app">
  <div ref="listScroll" class="scrolledList">
    <ul ref="scrolledHeight">
      <li v-for="month in months">
        {{month}}
      </li>               
    </ul>
  </div>

  <input type="text" placeholder="Add Month" v-model="month">
  <button @click="addMessage" @keyup.enter="addMessage"> Add Month</button>
</div>

<script src="https://unpkg.com/vue@next"> 
  Vue.createApp({data() {
      return {
        month: '',
        months: ['Jan', 'Feb', 'Apr', 'May', 'June', 'July', 'Aug']
      }
    },
    mounted() {this.updateScrollNextTick()
    },
    methods: {addMessage() {if(this.month == ''){return}

        this.months.push(this.month)
        this.month = ''
        this.updateScrollNextTick()},
      updateScrollNextTick () {
        let scrolledHeight = this.$refs.scrolledHeight.clientHeight

        this.$nextTick(() => {
          this.$refs.listScroll.scrollTo({
            behavior: 'smooth',
            top: scrolledHeight
          })
        })
      }
    },
  })
  .mount("#app")
</script>

示例地址:https://codepen.io/ammezie/pe…

次要局部:

运行后果:

在下面的代码片断中,咱们想在一个新我的项目被增加到列表中时取得平滑的向下滚动成果。浏览一下代码,尝试批改一下,去掉 nextTick,你就会失去那种平滑的滚动成果。你也能够尝试用setTimeout 来代替nextTick

总结

在本文中,咱们摸索了 nextTick 是如何工作的。咱们进一步理解了它与一般的 JavaScript setTimeout 的不同之处,并介绍了理论的用例。

~ 完,我是小智,筹备去教育一个前端小妹。

编辑中可能存在的 bug 没法实时晓得,预先为了解决这些 bug, 花了大量的工夫进行 log 调试,这边顺便给大家举荐一个好用的 BUG 监控工具 Fundebug。

原文:https://blog.logrocket.com/un…

交换

文章每周继续更新,能够微信搜寻 【大迁世界】 第一工夫浏览,回复 【福利】 有多份前端视频等着你,本文 GitHub https://github.com/qq449245884/xiaozhi 曾经收录,欢送 Star。

退出移动版