Vue源码阅读一:说说vue.nextTick实现

用法:

在下次 DOM 更新循环结束之后执行延迟回调。在修改数据之后立即使用这个方法,获取更新后的 DOM。

疑惑:

怎么实现的延迟回调

原理:

  1. JavaScript语言的一大特点就是单线程,同一个时间只能做一件事
  2. JavaScript任务可以分为两种,一种是同步任务,一种是异步任务
  3. 异步任务大致分为,宏任务,和微任务
  4. 所有同步任务都在主线程上执行,形成一个执行栈
  5. 主线程之外,还存在一个"任务队列"(task queue)。只要异步任务有了运行结果,就在"任务队列"之中放置一个事件。
  6. 一旦"执行栈"中的所有同步任务执行完毕,系统就会读取"任务队列"中的微任务,其次是宏任务,看看里面有哪些事件。那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
  7. 主线程不断重复上面的第6步。

vue实现:

vue 大多数情况下优先使用微任务, 很少的地方使用宏任务

vue nextTick 宏任务实现

  • 优先检测 setImmediate
if (typeof setImmediate !== ‘undefined‘ && isNative(setImmediate)) {
  macroTimerFunc = () => {
    setImmediate(flushCallbacks)
  }
}

setImmediate 浏览器支持情况

  • 其次检测 MessageChannel 支持情况
else if (typeof MessageChannel !== ‘undefined‘ && (
  isNative(MessageChannel) ||
  // PhantomJS
  MessageChannel.toString() === ‘[object MessageChannelConstructor]‘
)) {
  const channel = new MessageChannel()
  const port = channel.port2
  channel.port1.onmessage = flushCallbacks
  macroTimerFunc = () => {
    port.postMessage(1)
  }
}

MessageChannel 浏览器支持情况

  • 上面都不支持就使用最原始的setTimeout
 else {
  /* istanbul ignore next */
  macroTimerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}

vue nextTick 微任务实现

  • 优先检测 Promise
if (typeof Promise !== ‘undefined‘ && isNative(Promise)) {
  const p = Promise.resolve()
  microTimerFunc = () => {
    p.then(flushCallbacks)
    // in problematic UIWebViews, Promise.then doesn‘t completely break, but
    // it can get stuck in a weird state where callbacks are pushed into the
    // microtask queue but the queue isn‘t being flushed, until the browser
    // needs to do some other work, e.g. handle a timer. Therefore we can
    // "force" the microtask queue to be flushed by adding an empty timer.
    if (isIOS) setTimeout(noop)
  }
}

Promise 浏览器支持情况

  • 如果不支持Promise, 还是使用宏任务
else {
  // fallback to macro
  microTimerFunc = macroTimerFunc
}

vue中什么地方用宏任务,什么地方用微任务?

从源码中可以看出,在DOM事件中使用Vue.nextTick 默认使用宏任务, 其他地方使用Vue.nextTick默认使用微任务。

其实从源码中注释中可以看出Vue最开始都是使用微任务方式,后面出现了bug,才引入了宏任务方式

// Here we have async deferring wrappers using both microtasks and (macro) tasks.
// In < 2.4 we used microtasks everywhere, but there are some scenarios where
// microtasks have too high a priority and fire in between supposedly
// sequential events (e.g. #4521, #6690) or even between bubbling of the same
// event (#6566). However, using (macro) tasks everywhere also has subtle problems
// when state is changed right before repaint (e.g. #6813, out-in transitions).
// Here we use microtask by default, but expose a way to force (macro) task when
// needed (e.g. in event handlers attached by v-on).

产考资料:
JavaScript 运行机制详解:再谈Event Loop

原文地址:https://www.cnblogs.com/homehtml/p/11801626.html

时间: 2024-11-11 07:21:26

Vue源码阅读一:说说vue.nextTick实现的相关文章

Vue源码思维导图-------------Vue 初始化

上一节看完<Vue源码思维导图-------------Vue 构造函数.原型.静态属性和方法>,这节将会以new Vue()为入口,大体看下 this._init()要做的事情. 1 function Vue (options) { 2 if (process.env.NODE_ENV !== 'production' && 3 !(this instanceof Vue) 4 ) { 5 warn('Vue is a constructor and should be ca

Vue源码阅读笔记,持续更新

/ / Vue.js v2.1.3 源码阅读记录 使用的文件为使用es2015的本地文件 2018年4月20日 14:06:30 */ 第一章,Vuejs的整体架构 1. 入口 入口处使用一个闭包(function (global,factory) {factory()})(this,factory): 其中factory是工厂的意思,它的内部实现是一个工厂函数,其中直接声明的function为私有成员. 2. 生命周期的理解 理解vue的生命周期对通读vue源码的效率有较好的帮助,它的生命周期

[Vue源码]一起来学Vue模板编译原理(二)-AST生成Render字符串

本文我们一起通过学习Vue模板编译原理(二)-AST生成Render字符串来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsunlei/javascri

[Vue源码]一起来学Vue双向绑定原理-数据劫持和发布订阅

有一段时间没有更新技术博文了,因为这段时间埋下头来看Vue源码了.本文我们一起通过学习双向绑定原理来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsun

[Vue源码]一起来学Vue模板编译原理(一)-Template生成AST

本文我们一起通过学习Vue模板编译原理(一)-Template生成AST来分析Vue源码.预计接下来会围绕Vue源码来整理一些文章,如下. 一起来学Vue双向绑定原理-数据劫持和发布订阅 一起来学Vue模板编译原理(一)-Template生成AST 一起来学Vue模板编译原理(二)-AST生成Render字符串 一起来学Vue虚拟DOM解析-Virtual Dom实现和Dom-diff算法 这些文章统一放在我的git仓库:https://github.com/yzsunlei/javascrip

Vue源码思维导图------------Vue选项的合并之$options

本节将看下初始化中的$options: 1 Vue.prototype._init = function (options?: Object) { 2 const vm: Component = this 3 // a uid 4 vm._uid = uid++ 5 6 // a flag to avoid this being observed 7 vm._isVue = true 8 // merge options 9 if (options && options._isCompon

大白话Vue源码系列(01):万事开头难

阅读目录 Vue 的源码目录结构 预备知识 先捡软的捏 Angular 是 Google 亲儿子,React 是 Facebook 小正太,那咱为啥偏偏选择了 Vue 下手,一句话,Vue 是咱见过的最对脾气的 MVVM 框架.之前也使用过 knockout,angular,react 这些框架,但都没有让咱产生 follow 的冲动.直到见到 Vue,简直是一见钟情啊. Vue 的官方文档已经对 Vue 如何使用提供了最好的教程,建议 Vue 新手直接去官网学习,而不要在网上找些质量参差不齐的

Vue源码之响应式原理(个人向)

浅谈响应式原理 关于响应式原理,其实对于vue这样一个大项目来说肯定有很多细节和优化的地方,在下水平精力有限,不能一一尝试探索,本文仅以将响应式的大致流程个人向的梳理完毕为目的. 对于响应式主要分为三大部分来分析,1.响应式对象:2.依赖收集:3.派发更新. 最后将是个人的分析. 1.响应式对象 (Object.defineProperty) 我们先从初始化数据开始,再介绍几个比较核心的方法. 1.1.initState 文件位置:src/core/instance/state.js 在Vue的

Vue源码探究-虚拟DOM的渲染

Vue源码探究-虚拟DOM的渲染 在虚拟节点的实现一篇中,除了知道了 VNode 类的实现之外,还简要地整理了一下DOM渲染的路径.在这一篇中,主要来分析一下两条路径的具体实现代码. 按照创建 Vue 实例后的一般执行流程,首先来看看实例初始化时对渲染模块的初始处理.这也是开始 mount 路径的前一步.初始包括两部分,一是向 Vue 类原型对象上挂载渲染相关的方法,而是初始化渲染相关的属性. 渲染的初始化 下面代码位于vue/src/core/instance/render.js 相关属性初始