当前位置: 首页 > news >正文

网站建设专业性评价内容58同城成都网站建设名录

网站建设专业性评价内容,58同城成都网站建设名录,少儿编程哪个教育平台比较好,wordpress 发布文章功能修改前言 这篇文章分析了 Vue 更新过程中使用的异步更新队列的相关代码。通过对异步更新队列的研究和学习#xff0c;加深对 Vue 更新机制的理解 什么是异步更新队列 先看看下面的例子#xff1a; div idappdiv iddiv v-ifisShow加深对 Vue 更新机制的理解 什么是异步更新队列 先看看下面的例子 div idappdiv iddiv v-ifisShow被隐藏的内容/divinput clickgetDiv value按钮 typebutton/divscriptlet vm new Vue({el: #app,data: {//控制是否显示#divisShow: false},methods:{getDiv: function () {this.isShowtruevar content document.getElementById(div).innerHTML;console.log(content,content)}}}) /script上面的例子是点击按钮显示被隐藏的 div同时打印 div 内部 html 的内容。按照我们一般的认知应该是点击按钮能够显示 div 并且在控制台看到 div 的内部 html 的内容。 但是实际执行的结果确是div 可以显示出来但是打印结果的时候会报错错误原因就是 innerHTML 为 null也就是 div 不存在。 只有当我们再次点击按钮的时候才会打印出 div 里面的内容。这就是 Vue 的异步更新队列的结果 异步更新队列的概念 Vue 的 dom 更新是异步的当数据发生变化时 Vue 不是立刻去更新 dom而是开启一个队列并缓冲在同一个事件中循环发生的所有数据变化。 在缓冲时会去除重复的数据避免多余的计算和 dom 操作。在下一个事件循环 tick 中刷新队列并执行已去重的工作。 所以上面的代码报错是因为当执行 this.isShowtrue 时div 还未被创建出来知道下次 Vue 事件循环时才开始创建 查重机制降低了 Vue 的开销 异步更新队列实现的选择由于浏览器的差异Vue 会根据当前环境选择 Promise.then 或者 MuMutationObserver如果两者都不支持则会用 setImmediate 或者 setTimeout 代替 异步更新队列解析 异步队列源码入口 通过之前对 Vue 数据响应式的分析我们知道当 Vue 数据发生变化时会触发 dep 的 notify() 方法该方法通知观察者 watcher 去更新 dom我们先看一下这的源码 from src/core/observer/dep.js //直接看核心代码notify () {//这是Dep的notify方法Vue的会对data数据进行数据劫持该方法被放到data数据的set方法中最后执行//也就是通知更新操作// stabilize the subscriber list firstconst subs this.subs.slice()if (process.env.NODE_ENV ! production !config.async) {subs.sort((a, b) a.id - b.id)}for (let i 0, l subs.length; i l; i) {// 核心通知watcher进行数据更新//这里的subs[i]其实是Dep维护的一个watcher数组所以我们下面是执行的watcher中的update方法subs[i].update()}}上面的代码简单来说就是 dep 通知 watcher 尽心更新操作我们看一下 watcher 相关的代码 from :src/core/observer/watcher.js //这里只展示部分核心代码//watcher的update方法update () {/* istanbul ignore else *///判断是否存在lazy和sync属性if (this.lazy) {this.dirty true} else if (this.sync) {this.run()} else {//核心将当前的watcher放到一个队列中queueWatcher(this)}}上面 watcher 的 update 更新方法简单来说就是调用了一个 queueWatcher 方法这个方法其实是将当前的 watcher 实例放入到一个队列中以便完成后面的异步更新队列操作 异步队列入队 下面看看 queueWatcher 的逻辑 from src/core/observer/scheduler.js export function queueWatcher (watcher: Watcher) {const id watcher.id//去重的操作先判断是否在当前队列中存在避免重复操作if (has[id] null) {has[id] trueif (!flushing) {queue.push(watcher)} else {// if already flushing, splice the watcher based on its id// if already past its id, it will be run next immediately.let i queue.length - 1while (i index queue[i].id watcher.id) {i--}queue.splice(i 1, 0, watcher)}// queue the flushif (!waiting) {waiting trueif (process.env.NODE_ENV ! production !config.async) {flushSchedulerQueue()return}// 启动异步任务(刷新当前的计划任务)nextTick(flushSchedulerQueue)}}}上面这段 queueWatcher 的代码的主要作用就是对任务去重然后启动异步任务进行跟新操作。接下来我们看一线 nextTick 里面的操作 from src/core/util/next-tick.js //cb: export function nextTick (cb?: Function, ctx?: Object) {let _resolve//callbacks这个方法维护了一个回调函数的数组将回调函数添家进数组callbacks.push(() {//添加错误处理if (cb) {try {cb.call(ctx)} catch (e) {handleError(e, ctx, nextTick)}} else if (_resolve) {_resolve(ctx)}})if (!pending) {pending true//启动异步函数timerFunc()}// $flow-disable-lineif (!cb typeof Promise ! undefined) {return new Promise(resolve {_resolve resolve})}这里的核心其实就在 timerFunc 的函数上该函数根据不同的运行时环境调用不同的异步更新队列下面看一下代码 from src/core/util/next-tick.js /**这部分逻辑就是根据环境来判断timerFunc到底是使用什么样的异步队列**/let timerFunc//首选微任务执行异步操作Promise、MutationObserver//次选setImmediate最后选择setTimeout// 根据当前浏览器环境选择用什么方法来执行异步任务if (typeof Promise ! undefined isNative(Promise)) {//如果当前环境支持Promise则使用Promise执行异步任务const p Promise.resolve()timerFunc () {//最终是执行的flushCallbacks方法p.then(flushCallbacks)//如果是IOS则回退因为IOS不支持Promiseif (isIOS) setTimeout(noop)}//当前使用微任务执行isUsingMicroTask true} else if (!isIE typeof MutationObserver ! undefined (//如果当前浏览器支持MutationObserver则使用MutationObserverisNative(MutationObserver) ||MutationObserver.toString() [object MutationObserverConstructor])) {let counter 1const observer new MutationObserver(flushCallbacks)const textNode document.createTextNode(String(counter))observer.observe(textNode, {characterData: true})timerFunc () {counter (counter 1) % 2textNode.data String(counter)}isUsingMicroTask true} else if (typeof setImmediate ! undefined isNative(setImmediate)) {//如果支持setImmediate则使用setImmediatetimerFunc () {setImmediate(flushCallbacks)}} else {//如果上面的条件都不满足那么最后选择setTimeout方法来完成异步更新队列timerFunc () {setTimeout(flushCallbacks, 0)}}从上面代码可以看出不论 timerFunc 使用的是什么样的异步更新队列最终执行的函数还是落在了 flushCallbacks 上面那么我们来看一看这个方法到底是什么 from src/core/util/next-tick.js function flushCallbacks () {pending false//拷贝callbacks数组内容const copies callbacks.slice(0)//清空callbackscallbacks.length 0//遍历执行for (let i 0; i copies.length; i) {//执行回调方法copies[i]()}}上面的这个方法就是遍历执行了我们 nextTick 维护的那个回调函数数组, 其实就是将数组的方法依次添加进异步队列进行执行。同时清空 callbacks 数组为下次更新作准备。 上面这几段代码其实都是 watcher 的异步队列更新中的入队操作通过 queueWatcher 方法中调用的 nextTick(flushSchedulerQueue), 我们知道其实是将 flushSchedulerQueue 这个方法入队 异步队列的具体更新方法 所以下面我们看一下 flushSchedulerQueue 这个方法到底执行了什么操作 from src/core/observer/scheduler.js /**我们这里只粘贴跟本次异步队列更新相关的核心代码**///具体的更新操作 function flushSchedulerQueue () {currentFlushTimestamp getNow()flushing truelet watcher, id//重新排列queue数组是为了确保//更新顺序是从父组件到子组件//用户的watcher先于render 的watcher执行(因为用户watcher先于render watcher创建)//当子组件的watcher在父组件的watcher执行时被销毁则跳过该子组件的watcherqueue.sort((a, b) a.id - b.id)//queue数组维护的一个watcher数组//遍历queue数组在queueWatcher方法中我们将传入的watcher实例push到了该数组中for (index 0; index queue.length; index) {watcher queue[index]if (watcher.before) {watcher.before()}id watcher.id//清空has对象里面的id属性(这个id属性之前在queueWatcher方法里面查重的时候用到了)has[id] null//核心最终执行的其实是watcher的run方法watcher.run()//下面是一些警告提示可以先忽略if (process.env.NODE_ENV ! production has[id] ! null) {circular[id] (circular[id] || 0) 1if (circular[id] MAX_UPDATE_COUNT) {warn(You may have an infinite update loop (watcher.user? in watcher with expression ${watcher.expression}: in a component render function.),watcher.vm)break}}}//调用组件updated生命周期钩子相关先跳过const activatedQueue activatedChildren.slice()const updatedQueue queue.slice()resetSchedulerState()callActivatedHooks(activatedQueue)callUpdatedHooks(updatedQueue)if (devtools config.devtools) {devtools.emit(flush)} }上面的一堆 flushSchedulerQueue 代码简单来说就是排列了 queue 数组然后遍历该数组执行 watcher.run 方法。所以异步队列更新当我们入队完以后真正执行的方法其实是 watcher.run 方法 下面我们来继续看一下 watcher.run 方法到底执行了什么操作 from src/core/observer/watcher.js /*** Scheduler job interface.* Will be called by the scheduler.* 上面这段英文注释 是官方注释从这我们看出该方法最终会被scheduler调用*/run () {if (this.active) {//这里调用了watcher的get方法const value this.get()if (value ! this.value ||// Deep watchers and watchers on Object/Arrays should fire even// when the value is the same, because the value may// have mutated.isObject(value) ||this.deep) {// set new valueconst oldValue this.valuethis.value valueif (this.user) {try {this.cb.call(this.vm, value, oldValue)} catch (e) {handleError(e, this.vm, callback for watcher ${this.expression})}} else {this.cb.call(this.vm, value, oldValue)}}}}上述 run 方法最终要的操作就是调用了 watcher 的 get 方法该方法我们在之前的源码分析有讲过主要实现的功能是调用了 data 数据的 get 方法获取最新数据。 至此Vue 异步更新队列的核心代码我们就分析完了为了便于理清思路我们来一张图总结一下 关于 Vue.$nextTick 我们都知道 . n e x t T i c k 方 法 其 实 这 个 ∗ ∗ .nextTick 方法其实这个 ** .nextTick 方法其实这个∗∗nextTick** 方法就是直接调用的上面的 nextTick 方法 from src/core/instance/render.js Vue.prototype.$nextTick function (fn: Function) {return nextTick(fn, this)}由上面的代码我们可以看出$nextTick 是将我们传入的回调函数加入到了异步更新队列所以它才能实现 dom 更新后回调 注意$nextTick() 是会将我们传入的函数加入到异步更新队列中的但是这里有个问题如果我们想获得 dom 更新后的数据我们应该把该逻辑放到更新操作之后 因为加入异步队列先后的问题如果我们在更新数据之前入队的话 是获取不到更新之后的数据的 总结 总结起来就是当触发数据更新通知时dep 通知 watcher 进行数据更新这时 watcher 会将自己加入到一个异步的更新队列中。然后更新队列会将传入的更新操作进行批量处理。 这样就达到了多次更新同时完成提升了用户体验减少了浏览器的开销增强了性能。
http://www.hkea.cn/news/14458627/

相关文章:

  • 工信部网站验证码flash 网站
  • 中国小康建设网站办公室装修设计平面图
  • 浦东新区中国建设银行官网站网站开发怎么找客户
  • 个人企业网站怎么建设平台推广员是做什么的
  • 学术网站建设凡科网官网登录入口
  • 网站备案重要吗做网站新手流程
  • 郑州彩票网站建设软文网站平台
  • 怎么可以上传自己做的网站厦门市建设局网站首页
  • 滨州市网站建设中小型网站建设精英
  • 二手交易平台的网站怎么做做区块链网站需要注意哪些
  • 做理财网站 程序员 违法吗线上运营公司
  • 类似小红书网站开发费用东营建设网站
  • 鞍山网站广告咨询
  • 政务公开和网站建设先进个人金山区网站建设
  • 网站建设明细表厦门网站优化
  • 公司网站建设多少费用兴田德润在哪里外贸网站建站电话多少
  • 专门做试卷的网站吉林省建设安全信息网
  • 服装微信商城网站建设怎样下载网页上的视频
  • 山东省建设厅执业资格注册中心网站扬中新闻头条新闻
  • 企业网站功能模块编程入门自学软件
  • 个人网站备注模板通用网站后台管理 asp.net 源码
  • 天津市住房和城乡建设厅官方网站企业网站建设组织人员可行性分析
  • 江苏住房和建设厅网站新强生产建设兵团网站
  • 哈尔滨网站优化对策h5美食制作网站模板下载
  • 网站建设丶金手指花总11漳州建设项目公告网站
  • 服装网站的建设策划正规现货交易平台app
  • 做网站页面大小多大如何做一个网站推广自己的产品
  • 邢台移动网站建设价格株洲网站开发
  • 法学网站阵地建设2024近期新闻
  • 做徒步网站怎么样网站建设合同需要交印花税吗