从 JS Event Loop 机制看 Vue 中 nextTick 的实现原理

JS事件循环(Event Loop)详解 摘要: JavaScript事件循环机制通过协调同步任务、宏任务和微任务的执行顺序,实现单线程下的异步处理。执行流程为:执行全局Script(宏任务)→清空微任务队列→渲染页面→执行下一个宏任务。微任务(如Promise.then)优先级高于宏任务(如setTimeout),会在当前宏任务结束后全部执行。Async/Await本质是Promise语法糖,await后的代码作为微任务执行。实际应用中需注意微任务不阻塞渲染,避免无限递归,Vue的nextTick即利用微任务机制实现DOM更新。 阅读详情


本文来自作者 大师兄 在 GitChat 上分享「从 JS Event Loop 机制看 Vue 中 nextTick 的实现原理」,「阅读原文」查看交流实录

「文末高能」

编辑 | 泰龙

作为一名前端,一直以来以精通 Javascript 为目标。其实说实话精通真的挺难,不是你记住全部的 API 就算是精通。

JavaScript 的知识非常零散而庞杂,很多情况下上周学习的知识下周或是下个月就会忘记,给人的感觉就是好难学,怎么一直没进步呢?

我们不能仅限于语言本身,我们要透过语法看到深层次的运行机制。

掌握了 Javascript 运行机制,就好比学武术,大神级别都讲究「无招胜有招」。懂得了机制就可以举一反三,灵活运用。

事件循环机制(Event Loop),则是理解运行机制最关键的一个点。我们先抛出一个面试题:

setTimeout(function() {  console.log(1) }, 0); new Promise(function executor(resolve) {  console.log(2);  for( var i=0 ; i<10000 ; i++ ) {    i == 9999 && resolve();  }  console.log(3); }).then(function() {  console.log(4); }); console.log(5);

先思考,这段代码会输出什么?

单线程的 JavaScript

JavaScript 是单线程的,我想大家都不会怀疑吧。那什么是单线程?

当初我对「js 是单线程」的理解仅限于 js 的代码是一行一行执行的,不会出现同时执行两行的代码的情况,可是这个理解是太浅显,遇到异步请求就懵逼了,怎么不按我的想法走呢?还用说想法有问题呗。

所谓单线程,是指在 JS 引擎中负责解释和执行 JavaScript 代码的线程只有一个。JS 运行在浏览器中,是单线程的,每个 window 一个 JS 线程。

第一个问题,为啥要是单线程,多线程不好吗?减轻 cpu 的压力。现在如果有两个线程,一个线程修改页面某一个 dom 元素,正巧另一个线程将这个元素给删除了。这不是混乱了么。所以单线程是有原因的。

那你又有疑问了,既然是单线程的,在某个特定的时刻只有特定的代码能够被执行,并阻塞其它的代码。

那不行啊,我们总不能一直等着啊,前端需要调用后端接口取数据,这个过程是需要响应时间的,那执行这个代码的时候浏览器也等着?答案是否定的。

其实还有其他很多类线程(应该叫做任务队列),比如进行ajax请求、监控用户事件、定时器、读写文件的线程(例如在NodeJS中)等等。

这些我们称之为异步事件,当异步事件发生时,将他们放入执行队列,等待当前代码执行完成。就不会长时间阻塞主线程。

等主线程的代码执行完毕,然后再读取任务队列,返回主线程继续处理。如此循环这就是事件循环机制。

总结一下:

  1. 我们可以认为某个同域浏览器上下文中 JavaScript 只有一个主线程、函数调用栈以及多个任务队列。

  2. 主线程会依次执行代码,当遇到函数时,会先将函数入栈,函数运行完毕后再将该函数出栈,直到所有代码执行完毕。

  3. 当函数调用栈为空时,即会根据事件循环(Event Loop)机制来从任务队列中提取出待执行的回调并执行,执行的过程同样会利用函数栈。

  4. 所有同属一个的窗体都共享一个事件循环,所以它们可以同步交流。不同窗体之间相互独立,互不干扰。

你如果想彻底研究清楚事件模型,那还需要了解如下知识:

  • Javascript 的队列数据结构

  • Javascript 的执行上下文

  • 函数调用栈(call stack)

我们会分为两节来学习,队列数据结构为一节,执行上下文和函数调用栈合在一起为一节。

Javascript 的内存空间

队列数据结构

我们知道 Javascript 中有两种基本的种数据结构堆(heap)和栈(stack),还有一个队列(queue),并不是严格意义上的数据结构。

栈数据结构

在我们平时的工作过程中我们写 javascript 代码并不关心数据结构,但是它确实彻底理解某些运行机制的必不可少的部分。

JavaScript 中并没有严格的去区分栈内存与堆内存。我们平时基本都认为JavaScript 的所有数据(变量、函数)都保存在堆内存中。

但是在某些场景,我们仍然需要基于堆栈数据结构的思维(看好这里是思维)来看待,比如 JavaScript 的执行上下文。

要简单理解栈的存取方式,我们可以通过类比乒乓球盒子来分析。如下图左侧。

我们用栈存取数据的方式类比成乒乓球的存放方式,处于盒子中最顶层的乒乓球5,它一定是最后被放进去,但可以最先被使用。

而我们想要使用底层的乒乓球1,就必须将上面的4个乒乓球取出来,让乒乓球1处于盒子顶层。这就是栈空间先进后出,后进先出的特点。

堆数据结构

堆数据的存取数据的方式和与书架与书非常相似。

书架上放满了不同的书,我们只要知道书的名字我们就可以很方便的取出,而不用像从乒乓球盒子里取乒乓一样,非得将上面的所有乒乓球拿出来才能取到中间的某一个乒乓球。

在 JSON 格式的数据中,我们存储的 key-value 是可以无序的,我们并不关心顺序,我只要通过 key 取出 value 即可。

队列

在 JavaScript 中,理解队列数据结构的目的主要是为了理解事件循环(Event Loop)的机制。在后续的章节中我会详细分析事件循环机制。

队列是一种先进先出(FIFO)的数据结构。正如排队过安检一样,排在队伍前面的人一定是最先过检的人。用以下的图示可以清楚的理解队列的原理。

执行上下文 and 函数调用栈

这节我们稍微研究一下 JavaScript 中最基本的部分——执行上下文(Execution Context), 读完后,你应该清楚了解释器做了什么,为什么函数和变量能在声明前使用以及他们的值是如何决定的。

每当控制器转到可执行代码的时候,就会进入一个执行上下文。执行上下文可以理解为当前代码的执行环境,它会形成一个作用域。JavaScript 中的运行环境一般有两种:

  • 全局环境:JavaScript 代码运行起来会首先进入该环境

  • 函数环境:当函数被调用执行时,会进入当前函数中执行代码

其实这里还应该有一个 eval 环境,不推荐用 eval,今天也就不谈。

因此在一个 JavaScript 程序中,必定会产生多个执行上下文,JavaScript引擎会以栈的方式来处理它们,我们称其为函数调用栈(call stack)。

栈底永远都是全局上下文,而栈顶就是当前正在执行的上下文。

遇到以上两种情况,都会生成一个执行上下文,放入栈中,而处于栈顶的上下文执行完毕之后,就会自动出栈。

为了更加清晰的理解这个过程,根据下面的例子,结合图示给大家展示。

执行上下文可以理解为函数执行的环境,每一个函数执行时,都会给对应的函数创建这样一个执行环境。

modify.js

var name= 'dsx'; function modifyName() {    var secondName= 'gwj';    function swapName() {        var temp = secondName;        secondName= name;        name= temp ;    }     swapName(); } changeColor();

我们用 ECStack 来表示处理执行上下文组的堆栈。我们很容易知道,第一步,首先是全局上下文入栈。

全局入栈后,开始执行可执行代码,直到遇到了 modifyName(),这一句激活函数 modifyName 创建它自己的执行上下文,因此第二步就是 modifyName 的执行上下文入栈。

modifyName 入栈之后,继续执行函数内部可执行代码,遇到swapName()之后又激活了 swapName 执行上下文。因此第三步是 swapName 的执行上下文入栈。

在 swapName 的内部再没有遇到其他能生成执行上下文的代码,因此这段代码顺利执行完毕,swapName 的上下文从栈中弹出。

swapName 的执行上下文出栈后,继续执行 modifyName 其他可执行代码,也没有再遇到其他执行上下文,顺利执行完毕之后出栈。这样,ECStack中就只身下全局上下文了。

全局上下文在浏览器窗口关闭后出栈。

注意:
第一、函数中,遇到return能直接终止可执行代码的执行,因此会直接将当前上下文弹出栈。
第二、不要把执行上下文和作用域链混为一谈

如上我们演示了整个 modif.js 的执行过程。总结一下:

  • 单线程,依次自顶而下的执行,遇到函数就会创建函数执行上下文,并入栈

  • 同步执行,只有栈顶的上下文处于执行中,其他上下文需要等待

  • 全局上下文只有唯一的一个,它在浏览器关闭时出栈

  • 函数的执行上下文的个数没有限制

  • 每次某个函数被调用,就会有个新的执行上下文为其创建,即使是调用的自身函数,也是如此。

事件循环

现在我们知道 JavaScript 的单线程,以及这个线程中拥有唯一的一个事件循环机制。那什么事件循环机制是什么?且看下文分析。

JavaScript 代码的执行过程中,除了依靠函数调用栈来搞定函数的执行顺序外,还依靠任务队列(task queue)来搞定另外一些代码的执行。

根据上面的分析,任务队列的特点是先进先出。

一个 js 文件里事件循环只有一个,但是任务队列可以有多个。任务队列又可以分为 macro-task(task)与 micro-task(job)。

macro-task(task)包括:

  • setTimeout/setInterval

  • setImmediate

  • I/O操作

  • UI rendering

micro-task(job)包括:

  • process.nextTick

  • Promise

  • Object.observe(已废弃)

  • MutationObserver (html5 新特性)

浏览器中新标准中的事件循环机制与 node.js 类似,其中会介绍到几个nodejs有。

但是浏览器中没有的 API,大家只需要了解就好。比如 process.nextTick,setImmediate

我们称他们为事件源, 事件源作为任务分发器,他们的回调函数才是被分发到任务队列,而本身会立即执行。

例如,setTimeout 第一个参数被分发到任务队列,Promise 的 then 方法的回调函数被分发到任务队列(catch方法同理)。

不同源的事件被分发到不同的任务队列,其中 setTimeout 和 setInterval 属于同源

整体代码开始第一次循环。全局上下文进入函数调用栈。直到调用栈清空(只剩全局),然后执行所有的job。

当所有可执行的 job 执行完毕之后。循环再次从task开始,找到其中一个任务队列执行完毕,然后再执行所有的 job,这样一直循环下去。

无论是 task 还是 job,都是通过函数调用栈来完成。

这个时候我们是不是有一个大发现,除了首次整体代码的执行,其他的都有规律,先执行task任务队列,再执行所有的 job 并清空 job 队列。

再执行 task—job—task—job……,往复循环直到没有可执行代码。

那我们可不可以这么理解,第一次 script 代码的执行也算是一个task任务呢,如果这么理解那整个事件循环就很容易理解了。

来走一个栗子:

console.log(1); new  Promise(function(resolve){    console.log(2);    resolve(); }).then(function(){    console.log(3) }) setTimeout(function(){    console.log(4);    process.nextTick(function(){        console.log(5);     })    new  Promise(function(resolve){        console.log(6);        resolve()    }).then(function(){        console.log(7)    }) }) process.nextTick(function(){    console.log(8) }) setImmediate(function(){    console.log(9);    new  Promise(function(resolve){            console.log(10);            resolve()        }).then(function(){            console.log(11)        })       process.nextTick(function(){           console.log(12);        }) })

一下子写了这么多,是不是感觉有点复杂啊,不过没关系,我们一步一步来分析。

第一步,开始执行代码,global 入栈,执行到第一个 console.log(1),直接输出1。

第二步、执行遇到了 Peomise,Promise 构造函数的回调函数是同步执行,直接输出2。它的 then 方法才是任务源,将会分发一个 job 任务。

new  Promise(function(resolve){        console.log(2);        resolve();    }).then(function(){        console.log(3)    })

第三步、执行到 setTimeout,作为 task 任务分发源,分发一个任务出去。

setTimeout(function(){        console.log(4);        process.nextTick(function(){            console.log(5);         })        new  Promise(function(resolve){            console.log(6);            resolve()        }).then(function(){            console.log(7)        })    })

第四步、执行遇到 process.nextTick, 一个 job 任务分发器,分发一个 job 任务。

process.nextTick(function(){      console.log(8) })

第五步、执行遇到 setImmediate, 一个 task 任务分发器,分发一个 task 任务到任务队列。并且会在 setTimeout 的任务队列之后执行。

setImmediate(function(){       console.log(9);       new  Promise(function(resolve){               console.log(10);               resolve()           }).then(function(){               console.log(11)           })          process.nextTick(function(){              console.log(12);           }) })

这样 script 代码的第一轮执行完毕,在执行的过程中会遇到不同的任务分发器,分发到对应的任务队列。接下来将会执行所有的job队列的任务。

注意:nextTick 任务队列会比 Promise 的队列先执行(别问为什么,我也不知道)

这阶段会依次输出 8  3。

执行完所有的 job 任务后,就会循环下一次,从 task 开始,根据图示,会先执行 Time_out1 队列。

task 任务的执行也是要借助函数栈来完成,也就是说回到主线程。

会先依次输出4和6,然后依次分发 nextTick2 和 promise_then2 两个 job 任务。

第一个 task 任务执行完不会立即执行其他 task 任务,会执行刚才被分发的job 任务

在这个过程中会依次输出5和7

现在就剩下一个 task 任务 setIm1,按照同样的方式进行再次循环 。示意图如下:

以上阶段会依次输出9和10。

最后执行job任务,依次输出12和11。

完事,这个事件循环就完成了,我想是很清楚了。最终的输出结果是:

1,2,8,3,4,6,5,7,9,10,12,11

最后我们用 node 执行一下我们写的这个例子。结果如下:

Vue 中的 nextTick() 实现原理

new Vue({  el: '#app',  data: {    list: []  },  mounted: function () {    this.get()  },  methods: {    get: function () {      this.$http.get('/api/article').then(function (res) {        this.list = res.data.data.list        // this.$refs.list引用了ul元素,我想把第一个li颜色变为红色        this.$refs.list.getElementsByTagName('li')[0].style.color = 'red'      })    },  } })

我在获取到数据后赋值给 data 对象的 list 属性,然后我想引用ul元素找到第一个li把它的颜色变为红色,但是事实上,这个要报错的。

我们知道,在执行这句话时,ul 下面并没有 li,也就是说刚刚进行的赋值操作,当前并没有引起视图层的更新。

因为 Vue 的数据驱动视图更新,是异步的,即修改数据的当下,视图不会立刻更新,而是等同一事件循环中的所有数据变化完成之后,再统一进行视图更新。

因此,在这样的情况下,vue 给我们提供了 $nextTick 方法,如果我们想对未来更新后的视图进行操作,我们只需要把要执行的函数传递给 this.$nextTick 方法,vue 在更新完视图后就会执行我们的函数帮我们做事情。

$nextTick() 原理:

Vue 在内部尝试对异步队列使用原生的 Promise.then 和 MutationObserver,如果执行环境不支持,会采用 setTimeout(fn, 0) 代替。

看过上一个chat(Vue.2x 源码分析之响应式原理)的同学应该有了解,vue里面有一个watcher,用于观察数据的变化,数据有变化就会更新dom。

但是vue并不是每次数据改变都会立即触发更新dom,而是将这些操作都缓存在一个队列,如果同一个 watcher 被多次触发,只会一次推入到队列中。这样可以避免不必要的重复计算和 DOM 操作,提升性能。

那什么时候更新DOM呢?在下一个事件循环“tick”中,Vue 刷新队列并执行,统一执行(已去重的)dom的更新操作。

在前面我们花了大量篇幅来介绍javascript的事件循环机制,应该知道事件循环中有两种任务队列, macro-task(task) 和 micro-task(job)。

引擎在每个 task 执行完毕,从队列中取下一个 task 来执行之前,会先执行完所有 micro-task(job)队列中的 job。

setTimeout 任务源会分配回调到一个新的 task 中执行,而 Promise 的 then、MutationObserver 的回调都会被安排到一个新的 job 中执行,会比 setTimeout 产生的 task 先执行。

想要要创建一个新的 job,优先使用 Promise,如果浏览器不支持,再尝试 MutationObserver。实在不行,只能用 setTimeout 创建 task 了。

为啥要用 job?根据 HTML Standard,在每个 task 运行完以后,UI 都会重渲染,那么在 job 中就完成数据更新,当前 task 结束就可以得到最新的 UI 了。反之如果新建一个 task 来做数据更新,那么渲染就会进行两次。

总结 $nextTick 触发的时机:

同一事件循环中的代码执行完毕 -> DOM 更新 -> nextTick callback触发

$nextTick 源码:

//首先,这个函数是采用了一个单利模式还是什么创建的一个闭包函数 export  const  nextTick = (function(){    // 缓存函数的数组    var callbacks = [];    // 是否正在执行      var pending = false;      // 保存着要执行的函数    var timerFunc;   })()

首先定义一些变量,供后面调用。接下来是一个函数:

//执行并且清空所有的回调列表  function nextTickHandler() {    pending = false;    //拷贝出函数数组副本    const copies = callbacks.slice(0);    //把函数数组清空    callbacks.length = 0;    //依次执行函数    for (let i = 0; i < copies.length; i++) {      copies[i]();    }  }

这个函数就是 $nextTick 内实际调用的函数。

接下来,是 vue 分了三种情况来延迟调用以上这个函数,因为 $nextTick 目的就是把传进来的函数延迟到 dom 更新后再使用,所以这里依次优雅降序的使用 js 的方法来做到这一点。

利用 promise.then 延迟调用

if (typeof Promise !== 'undefined' && isNative(Promise)) {  var p = Promise.resolve();  var logError = function (err) { console.error(err); };  timerFunc = function () {    p.then(nextTickHandler).catch(logError);    // 在部分 iOS 系统下的 UIWebViews 中,Promise.then 可能并不会被清空,因此我们需要添加额外操作以触发    if (isIOS) { setTimeout(noop); }  };

如果浏览器支持 Promise,那么就用 Promise.then 的方式来延迟函数调用, Promise.then 方法可以将函数延迟到当前函数调用栈最末端,也就是函数调用栈最后调用该函数。从而做到延迟。

MutationObserver 监听变化

else if (typeof MutationObserver !== 'undefined' && (  isNative(MutationObserver) ||  MutationObserver.toString() === '[object MutationObserverConstructor]' )) {  / 当 Promise 不可用时候使用 MutationObserver  var counter = 1;  var observer = new MutationObserver(nextTickHandler);  var textNode = document.createTextNode(String(counter));  observer.observe(textNode, {    characterData: true  });  timerFunc = function () {    counter = (counter + 1) % 2;    textNode.data = String(counter);  }; }

MutationObserver 是 h5 新加的一个功能,其功能是监听dom节点的变动,在所有 dom 变动完成后,执行回调函数。

具体有一下几点变动的监听:

  1. childList:子元素的变动

  2. attributes:属性的变动

  3. characterData:节点内容或节点文本的变动

  4. subtree:所有下属节点(包括子节点和子节点的子节点)的变动

可以看出,先创建了一个文本节点,来改变文本节点的内容来触发的变动,因为我们在数据模型更新后,将会引起 dom 节点重新渲染。

所以,我们加了这样一个变动监听,用一个文本节点的变动触发监听,等所有dom渲染完后,执行函数,达到我们延迟的效果。

setTimeout 延迟器

else {    timerFunc = function () {      setTimeout(nextTickHandler, 0);    };  }

这个很简单哈。利用 setTimeout 的延迟原理,setTimeout(func, 0)会将 func 函数延迟到下一次函数调用栈的开始,也就是当前函数执行完毕后再执行该函数,因此完成了延迟功能。

但是我们看到的 $nextTick 是一个函数啊,这里就是一个自执行函数,并不是一个函数啊,没错我们还需要返回一个闭包函数才可以。往下看:

闭包函数

return function queueNextTick (cb, ctx) {    var _resolve;    callbacks.push(function () {      if (cb) { cb.call(ctx); }      if (_resolve) { _resolve(ctx); }    });    // 如果没有函数队列在执行才执行    if (!pending) {      pending = true;      timerFunc();    }    // promise化    // 如果没有传入回调,则表示以异步方式调用    if (!cb && typeof Promise !== 'undefined') {      console.log('进来了')      return new Promise(function (resolve) {        _resolve = resolve;      })    }  }

这个 return 的函数就是我们实际使用的闭包函数,每一次调用$nextTick函数,都会向 callbacks 这个函数数组入栈。

然后监听当前是否正在执行,如果没有,执行函数。下面一个 if 是 promise 化,如果没有传入回调,则表示以异步方式调用。

后记

现在 Vue()的 nextTick 实现移除了 MutationObserver 的方式(兼容性原因),取而代之的是使用 MessageChannel ( https://developer.mozilla.org/zh-CN/docs/Web/API/MessageChannel )。

并且加入了 setImmediate。

有兴趣的同学可以继续去学习,原理我们已经说的很明白。源码:https://github.com/vuejs/vue/blob/dev/src/core/util/next-tick.js

近期热文

《手把手教你如何向 Linux 内核提交代码》

《Java 实现 Web 应用中的定时任务》

《沉迷前端,无法自拔的人,如何规划职业生涯?》

《TensorFlow 计算与智能基础》

《突破技术发展瓶颈、成功转型的重要因素》

《Selenium 爬取评论数据,就是这么简单!》

给你一个不学 Vue 的理由

「阅读原文」看交流实录,你想知道的都在这里

Vue学习记录之十九 Event Loop,宏任务和微任务 当一个宏任务执行完毕后,会检查是否有微任务队列,如果有,则将微任务队列中的所有任务依次执行完毕,然后再继续选择下一个宏任务执行。这样的过程循环进行,形成了事件循环。微任务通常在宏任务执行完毕后立即执行,因此微任务具有更高的优先级,可以在页面渲染前执行,从而提供更好的用户体验。微任务的优先级高于宏任务,因此微任务会在本轮宏任务执行结束后立即执行,而不是等到下一个事件循环。按顺序执行, 同步任务直接执行,异步任务进入异步队列,执行完以后,在进行入异步列队,然后在看是同步还是异步任务,如此循环执行。 阅读详情

相关推荐

解读vue源码之nextTick:何谓 event-loop, 浏览器的事件机制,task/microtasks

前言: 目录: nextTick 与异步渲染UI 浏览器的event-loop nextTick 与异步渲染UI 浏览器的event-loop

凝视深渊 832

Vue中nexttick

nexttick是什么? 官方的定义: 在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM 用法: 接收一个回调函数作为参数,作用是将回调函数延迟到下一次dom更新完毕后使用。如果没有传入回调函数,并且在支持promise的环境中,会返回一个promise对象 使用场景: 在对数据进行赋值之后,需要对新dom做一些操作的时刻,但是此刻最新的dom还没有进行更新。 为什么数据赋值后,不会立马更新dom 原因: vue 更新dom是异步执行的。监听到

qq_39692513的博客 1万+

深入理解JavaScript Event Loop:异步编程与性能优化的核心机制

在计算机科学中,并发模型是处理多任务的核心机制,它决定了程序如何高效地执行。JavaScript采用单线程事件驱动模型,通过Event Loop实现非阻塞异步操作。其原理基于调用栈、任务队列和微任务队列的协同工作:主线程执行同步代码,异步回调被放入队列,Event Loop循环调度确保任务有序执行。这一机制的技术价值在于,它使得单线程JavaScript能够处理高并发I/O操作,避免界面卡顿,提升用户体验。在应用场景上,Event Loop是理解现代前端框架如Vue的nextTick、React调度器的基础

weixin_31742871的博客 243

vue中nextTick()的理解及使用

一、$nextTick的定义及理解: 定义:在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。 所以就衍生出了这个获取更新后的DOM的Vue方法。所以放在Vue.nextTick()回调函数中的执行的应该是会对DOM进行操作的 js代码; 理解:nextTick(),是将回调函数延迟在下一次dom更新数据后调用,简...

weixin_42333548的博客 1万+

【Vue知识点总结】nextTick:驾驭异步更新机制

机制:Vue 是异步更新 DOM,数据变化到 DOM 渲染存在时间差。作用: nextTick 用于在 DOM 更新循环结束之后执行延迟回调。本质:利用事件循环的微任务来实现批处理和延迟执行。

这是个栗子的博客 474

tick:Tick是一个JavaScript插件,可让您轻松直观地看到动态变化的数字

打钩 Tick是一个JavaScript插件,可轻松实现动态可视化数字变化。 实例方法 注意: $().ticker始终返回Tick实例的数组,因此请始终在该数组的元素上调用这些方法! start渲染并启动Tick实例。 返回实例的计时器;如果实例已经在运行,则返回undefined 。 stop停止Tick实例并清除计时器。 返回false 。 属性 running boolean表示行情自动收录器是否已启动 options反对所有运行时选项 element对象用于此行情收录器的元素 value int传递给代码的任何值 separators数组所有分隔符的列表 increment函数回调,用于在每个刻度上更新@value 选项 incremental混合可以是在每个刻度上添加到基值的固定数值,也可以是用当前值调用并且必须返回更新后的数字的函数 delay int时间(以毫秒为单位)

Vue中的$nextTick详解(三分钟吃透)

我们可以理解成,Vue 在更新 DOM 时是异步执行的。当数据发生变化,Vue将开启一个异步更新队列,视图需要等队列中所有数据变化完成之后,再统一进行更新

常来常往,共同成长 7759

从CD4051到现代模拟开关:40年芯片演进史与选型避坑指南

本文回顾了从CD4051到现代模拟开关的40年技术演进,详细对比了导通电阻、带宽等关键参数的显著提升。通过实际案例和选型矩阵,揭示现代模拟开关在精度、功耗和集成度方面的优势,并提供高精度测量、电池供电等场景的选型策略与避坑指南,帮助工程师优化设计。

weixin_42543046的博客 153

Vue中nextTick一文详解

nextTick在这篇文章中,我们详细介绍了 Vue 中的nextTick。我们介绍了nextTick的基本概念、使用方法、原理以及应用场景。需要注意的是,nextTick是一个非常重要的 API,它可以帮助我们在更新 DOM 后获取更新后的 DOM 状态,执行依赖于 DOM 的操作和第三方库。因此,在实际应用中,我们需要根据具体情况灵活运用nextTick。以下是一个表格,列出了本文中介绍的nextTick知识点示例代码nextTick的基本概念nextTick的使用方法nextTick的原理。

five-five 7596

Qt绘图实战:用QGraphicsItem实现可拖拽箭头连接(附完整代码)

本文详细介绍了如何使用Qt的QGraphicsItem框架实现一个功能完备的可拖拽箭头连接组件。通过核心代码示例,讲解了如何创建自定义图形项、实现智能吸附、碰撞检测以及实时拖拽编辑路径,为构建流程图、拓扑图等专业图形编辑器提供了完整的解决方案。

m2n3b4v5c6的博客 625

ROS入门(一)——ROS安装(vmware16+ubuntu20.04+ROS-Noetic)

嵌套:ROS可以在Ubuntu上运行,Ubuntu在虚拟机Vmware中安装。 从 虚拟机vmware安装→ubuntu安装→ros安装,逐步介绍安装ROS环境的过程。整个过程是我一步步跟着各种博客安装实现的,亲测可行。 版本: Vmware :Vmware Workstation16 Ubuntu :20.04 ROS :Noetic 其中vmware直接载当前最新版本就好,而ubuntu的版本要注意一下。 在ROS官网(cn - ROS Wiki),我们进入到ROS安装的步骤界面,可以看..

Netceor的博客 9737

Vue中nextTick()的理解

本文深入解析了JavaScript事件循环机制和Vue的异步更新策略。第一部分详细介绍了执行栈、任务队列(宏任务与微任务)以及事件循环的工作原理,并通过示例展示了代码执行顺序。第二部分阐述了Vue采用异步更新的原因及实现方式,重点讲解了nextTick的原理和使用场景,指出其本质是将回调放入微任务队列。文章特别强调nextTick的正确使用时机,并分析了在微任务队列中不同任务顺序对结果的影响,为开发者在数据变更后获取最新DOM状态提供了实用指南。

zheshiyangyang的博客 3267

AI变现案例实战系列4:AI数字员工团队——用OpenClaw搭建6个智能体,自动运营你的赚钱系统

摘要:谷歌AI产品经理Shubham Saboo利用OpenClaw搭建6人AI团队,实现内容创作、技术开发等任务自动化,每月成本不足400美元。文章对比阿里云和Windows本地两种部署方案,提供详细配置指南。通过多Agent架构实现物理隔离与精准协作,可创建6个专业AI角色(如研究员、运营、工程师等),每个Agent专注单一任务,避免记忆负担和上下文污染问题。阿里云方案适合长期稳定运行,Windows本地部署则适合零成本测试。最终可组建高效AI团队,实现7x24小时无人值守运营。(149字)

小明的博客 1141

技术文章 | JavaScript Event Loop机制详解与Vue.js中nextTick的实践应用

本文依次介绍了函数调用栈、MacroTask 与 MicroTask 执行顺序、浅析 Vue.js 中 nextTick 实现等内容;本文中引用的参考资料统一声明在 JavaScript 学习与实践资料索引。

CS13522431352的博客 436

YOLOv11 + TensorRT 在 Jetson 设备上的实时部署

YOLOv11 + TensorRT 在 Jetson 设备上的实时部署

p6666666668的博客 1588

Alphafold2/multimer Conda环境配置与GPU加速优化指南

本文详细介绍了如何在本地服务器或工作站上,通过Conda环境配置并优化GPU加速来部署Alphafold2及其多聚体版本Alphafold2-multimer。内容涵盖从硬件准备、依赖安装、数据库部署到实战预测与常见报错处理的全流程,重点解决了本地安装过程中的依赖冲突与GPU调用失败等关键问题,帮助研究人员高效运行这一蛋白质结构预测工具。

neovim7hacker的博客 468

Vue2.0源码阅读笔记(四):nextTick

  在阅读 nextTick 的源码之前,要先弄明白 JS 执行环境运行机制,介绍 JS 执行环境的事件循环机制的文章很多,大部分都阐述的比较笼统,甚至有些文章说的是错误的,以下为个人理解,如有错误,欢迎指正。 一、浏览器中的进程与线程   以 chorme 浏览器为例,浏览器中的每个页面都是一个独立的进程,在该进程中拥有多个线程,通常有以下几个常驻线程: 1、GUI 渲染线程 2、JavaSc...

weixin_30735391的博客 127

【实践指南】Wasserstein距离在电力系统鲁棒优化中的核心应用

本文深入探讨了Wasserstein距离在电力系统分布鲁棒优化中的核心应用。针对风电、光伏出力的不确定性,文章阐述了如何利用Wasserstein距离构建模糊集,将复杂的分布鲁棒优化问题转化为可求解的确定性模型,并提供了从理论到代码实现的完整实践指南,有效平衡了系统运行的经济性与鲁棒性。

weixin_29229261的博客 306

vue 调用浏览器的打印功能_通俗易懂的Vue异步更新策略及 nextTick 原理

作者:hello等风来转发链接:https://juejin.im/post/5eccc77c6fb9a047ab2c13c4前言最近在学习一些底层方面的知识。上一篇:《通俗易懂的Vue响应式原理以及依赖收集》,所以想做个系列尝试去聊聊这些比较复杂又很重要的知识点。学习就好比是座大山,只有自己去登山,才能看到不一样的风景,体会更加深刻。今天我们就来聊聊Vue中比较重要的异步更新策略及 nextTi...

weixin_39593498的博客 425

【Dify】36氪新闻热榜智能自动化采集与AI处理

本文介绍如何利用Dify等自动化工具实现36氪新闻热榜的智能采集与处理。通过HTTP请求节点获取数据,JSON解析节点结构化处理,AI处理节点生成智能摘要,最终格式化输出结果。工作流程包含数据获取、解析、AI摘要、文本整理和内容输出五个环节,支持批量化、定制化的新闻处理需求。该方案适用于行业监测、内容创作、舆情管理等场景,显著提升信息获取效率,实现"所需即得"的自动化新闻服务。系统采用OpenAI GPT和Dify API作为核心模型,无需复杂人工干预即可完成全流程处理。

Mr数据杨 595

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

从JS事件循环(Event Loop)机制到vue.nextTick的实现

众所周知,为了与浏览器进行交互,Javascript是一门非阻塞单线程脚本语言。 为何单线程? 因为如果在DOM操作中,有两个线程一个添加节点,一个删除节点,浏览器并不知道以哪个为准,所以只能选择一个主线程来执行代码,以防止冲突。虽然如今添加了webworker等新技术,但其依然只是主线程的子线程,并不能执行诸如I/O类的操作。长期来看,JS将一直是单线程。 为何非阻塞?因为单线...

LEI20012000的博客 824

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

结合Event Loop谈谈对Vue中nextTick的理解

本文结构- 带着问题看这篇文章-event loop中任务的执行顺序-微任务 & 宏任务- Vue中nextTick的实现-对nex...

zsy666666的博客 479

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

JS事件循环搞不懂?前端打工人必看的Event Loop通关秘籍

写到这,估计你也看累了。但你发现没有,Event Loop这玩意儿,面试时背再多的"先宏后微"、“Node六个阶段”,都不如在实际项目中踩过一次坑来得深刻。我印象最深的一次,是早年负责的一个可视化项目,有大量的WebGL渲染和数据更新。当时没理解透rAF和setTimeout的区别,用setTimeout做动画循环,结果用户电脑卡顿时,setTimeout还在那傻乎乎地执行,积了一堆回调,等CPU缓过来瞬间爆炸,页面卡死。

master_chenchen的博客 946

vue nextTick + 事件循环机制

eventLoop,事件循环机制,vue,nextTick,进程,线程

趟过java,遇见web 2420
上一篇: 抖音 K.O. 快手之后还能火多久?
下一篇: 视频的「编解码」与「传输」的那些事儿
软件供应链安全
软件供应链安全 领域专家: 后端开发技术领域 领域专家: 后端开发技术领域
博客等级 码龄9年 1万+粉丝 347原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值