当前位置: 网站首页>小程序开发>小程序制作

义乌网站建设_营销型企业网站制作_专业网页定制开发-网络推广公司

发表日期: 2021-06-17 15:36:16 浏览次数:269

义乌网站建设_营销型企业网站制作_专业网页定制开发-网络推广公司


网站建设.jpg


义乌市,隶属于浙江省金华市,古称“乌伤”,金华-义乌(浙中)和杭州(浙北)、宁波(浙东)、温州(浙南)并列浙江四大区域中心城市;位于浙江省中部,地处金衢盆地东部,市境东、南、北三面群山环抱,南北长58.15公里,东西宽44.41公里,面积1105.46平方公里。截至2019年,义乌市户籍人口83.6万人,实现地区生产总值1421.1亿元。 [1]  先后出了“初唐四杰”之一骆宾王、宋代名将宗泽、金元四大名医之一朱丹溪及现代教育家陈望道、文艺理论家冯雪峰、历史学家吴晗等历史名人。

义乌是中国首个也是唯一一个在县级市国家级综合改革试点,先后被授予中国国家卫生城市、国家环保模范城市、中国优秀旅游城市、国家园林城市、国家森林城市和浙江省文明示范市等荣誉称号。义乌国际商贸城被中国国家旅游局授予中国首个AAAA级购物旅游区。义乌是中国大陆六大强县(市)之一,人均收入水平、豪车密度在中国大陆居首位,是中国最富裕的地区之一,在福布斯发布2013中国最富有10个县级市排名第一。 义乌是全球最大的小商品集散中心,被联合国、世界银行等国际权威机构确定为世界第一大市场。义乌被列为第一批国家新型城镇化综合试点地区。2019全国营商环境百强县、2019年全国综合经济竞争力第六名。 [2] 

2020年7月,全国爱卫会确认义乌市为2019年国家卫生城市 [3]  ;同年11月,入选“第六届全国文明城市名单”。 [4]  2020年12月,社科院发布《全国县域经济综合竞争力100强》,义乌排名第7 [5]  。


正文

开始前,我觉得我们需要先弄清楚vue的$nextTick是干什么用的,它的存在是为了解决什么问题?大家也可以自问一下。

nextTick英文翻译过来“下一个记号或者标记”,我觉得这里应该用状态来描述更加合理一些。

上面,我抛了一个问题,现在来聊一聊这个问题,首先说一说nextTick的作用,这里我就直接引用官网api上的一句话,我觉得已经说的非常清楚了:将回调延迟到下次 DOM 更新循环之后执行。在修改数据之后立即使用它,然后等待 DOM 更新。它跟全局方法 Vue.nextTick 一样,不同的是回调的 this 自动绑定到调用它的实例上

再看一下官网的例子:

new Vue({  // ...
  methods: {    // ...
    example: function () {      // 修改数据
      this.message = 'changed'
      // DOM 还没有更新
      this.$nextTick(function () {        // DOM 现在更新了
        // `this` 绑定到当前实例
        this.doSomethingElse()
      })
    }
  }
})

上面我用了官网的例子和解释,我觉得例子还没完全说明白nextTick解决了什么样的问题,所以我觉得我需要补充一下我自己的理解。
大家都知道,在vue的created生命周期里面,如果你需要在这个生命周期钩子里面操作dom是不行的,因为这个钩子执行的时候dom并没有渲染到页面上,所以会直接报错。
这里有的同学就说,如果我必须要在这里操作dom呢?那这个时候就到了$nextTick登场的时候,根据官方的解释和例子也可以证明这一点,nextTick的参数回调函数执行的时候就是dom已经渲染到了页面,挂载好了,并且把当前this绑定到了当前的实例上面去了,这个时候就可以获取到更新后的dom元素去操作dom。
其实真正的用意,并不是为了解决这个,其实是为了解决响应式更新的问题。
我们都知道,vue是响应式的,什么是响应式?简单说,就是数据变了,视图变,视图变了,数据变。这样一来就有一个问题,不知道大家发现了没,如果没发现,我们就先看一下下面这段代码

<template>
  <div>
    {{a}}
    {{b}}
    {{c}}  </div></template>
new Vue({
  data () {    return {      a: 1,      b: 2,      c: 3
    }
  },
  created () {    this.a = 2
    this.b = 3
    this.c = 4
  }
})

上面这段代码看似很简单,对不对。但是这里有一个很有趣的事,大家先想一想,我们说了vue是响应式的,那当我们this.a做重新赋值的时候是不是就把a的值进行修改了,那修改了是不是就应该要触发页面的更新,把最新的值显示到页面上去,按理来说应该会更新三次对吧,因为我们先修改了a,然后修改b,最后修改的是c,但是结果告诉我们页面只更新了一次,为什么呢?
说到底,这是因为nextTick方法在里面作怪,我觉得这个做法非常聪明,这样可以将性能损失降到最小。
这里只更新一次是因为在源码上,在收集更新Wathcer时将更新通过nextTick方法做了延迟执行,所以当更新的时候,是先把所有的更新Wathcer收集了起来,然后调用nextTick方法做延迟更新的执行,这样一来,赋值操作就是在前一直更新数据,更新就会不断的添加更新Wathcer到队列中,最后只需要拿出队列中的所有更新Wathcer去进行挨个更新,这样一来就会是现在看到的这样,在赋值的时候并不会马上更新反应到页面,而是会先等你的赋值都做完后,最后统一更新,这样就解决了页面更新频率问题。

下面我们来看看官方的对应源码,来证明一下我说的是不是这样的。代码位置在github对应:vue/blob/dev/src/core/observer/scheduler.js文件中,大家可以去看一下

/**
 * Push a watcher into the watcher queue.
 * Jobs with duplicate IDs will be skipped unless it's
 * pushed when the queue is being flushed.
 */export function queueWatcher (watcher: Watcher) {  const id = watcher.id  if (has[id] == null) {
    has[id] = true
    if (!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 - 1
      while (i > index && queue[i].id > watcher.id) {
        i--
      }
      queue.splice(i + 1, 0, watcher)
    }    // queue the flush
    if (!waiting) {
      waiting = true

      if (process.env.NODE_ENV !== 'production' && !config.async) {
        flushSchedulerQueue()        return
      }      // 这里就是延迟更新的处理 - 使用nextTick去解决频繁更新的问题。
      // 上面的那些代码是在做watcher收集
      nextTick(flushSchedulerQueue)
    }
  }
}

上面说完了使用,下面就是干货了,我们来说说nextTick的原理实现,分析一下源码是怎么写的。

源码分析

源码对应位置在github的vue/blob/dev/src/core/util/next-tick.js文件

/* @flow *//* globals MutationObserver */import { noop } from 'shared/util'import { handleError } from './error'import { isIE, isIOS, isNative } from './env'export let isUsingMicroTask = falseconst callbacks = [] // 存放收集的nextTick第一参数的回调函数let pending = false // 状态开关// 该函数将异步执行时 处理队列中收集到的所有回调 挨个执行function flushCallbacks () {
  pending = false
  // 将队列中的回调全部赋值给copies
  const copies = callbacks.slice(0)
  callbacks.length = 0 // 清空队列
  // 遍历当前的队列,挨个执行回调
  for (let i = 0; i < copies.length; i++) {
    copies[i]()
  }
}// 定义一个 最后可拿到异步处理方式的变量let timerFunc// 如果当前环境支持promise ,那么异步的处理将使用promise去做延迟执行if (typeof Promise !== 'undefined' && isNative(Promise)) {  const p = Promise.resolve() // 获得一个完成状态的promise
  // 将promise的异步处理函数赋值给 timerFunc
  timerFunc = () => {
    p.then(flushCallbacks) // 执行then函数,将执行收集到的调用队列处理函数执行

    if (isIOS) setTimeout(noop)
  }
  isUsingMicroTask = true} else if (!isIE && typeof MutationObserver !== 'undefined' && 
  isNative(MutationObserver) ||  // PhantomJS and iOS 7.x
  MutationObserver.toString() === '[object MutationObserverConstructor]')) {  // 环境不支持promise但支持 MutationObserver,将会用MutationObserver做为异步执行处理

  // (#6466 MutationObserver is unreliable in IE11)
  let counter = 1
  const observer = new MutationObserver(flushCallbacks)  const textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
  isUsingMicroTask = true} else if (typeof setImmediate !== 'undefined' && isNative(setImmediate)) {  // Fallback to setImmediate.
  // Techinically it leverages the (macro) task queue,
  // but it is still a better choice than setTimeout.
  // 当前环境如果不支持 promise 与 MutationObserver ,如果支持setImmediate,将会使用setImmediate做为异步执行处理
  timerFunc = () => {
    setImmediate(flushCallbacks)
  }
} else { 
  // 如果当前环境不支持以上三种异步方式,将直接使用setTimeout定时器做为异步处理
  // Fallback to setTimeout.
  timerFunc = () => {
    setTimeout(flushCallbacks, 0)
  }
}// 这个就是nextTick函数,参数两个:回调,上下文export function nextTick (cb?: Function, ctx?: Object) {  let _resolve  // 向队列中添加收集的回调,这里要注意,push时加了一层函数包装
  callbacks.push(() => {    if (cb) { // 判断是否传递了 回调
      try {
        cb.call(ctx) // 通过call方法执行回调函数,并设置函数内部this指向到当前上下文
      } catch (e) {         // 如果函数一旦执行报错,将抛错
        handleError(e, ctx, 'nextTick')
      }
    } else if (_resolve) { 
    // 当不是一个回调时,执行promise的resolve方法,将状态变为完成,并传入当前上下文对象作为完成时的入参
      _resolve(ctx)
    }
  })  if (!pending) { // 这是一个等待状态开关
    pending = true // 等待当前的处理完后才开始下一次的
    timerFunc() // 这是一个关键函数,主要是做异步操作,并且针对各种情况做了兼容的不同处理
  }  // $flow-disable-line
  // 如果没有回调函数,并且当前的环境支持promise,就直接返回一个promise
  if (!cb && typeof Promise !== 'undefined') {    return new Promise(resolve => {
      _resolve = resolve
    })
  }
}

以上源码我做了注释,如果有不同见解的欢迎指正。
最后需要说一下重点的一个变量,就是timerFunc变量,它的最后值决定当前nextTick异步实现的处理方式,代码会挨个顺序判断兼容情况,最后选择一个最适合的方式:Promise,MutationObserver, setImmediate,setTimeout


义乌网站建设_营销型企业网站制作_专业网页定制开发-网络推广公司

400-111-6878
服务热线
顶部

备案号: 苏ICP备11067224号

CopyRight © 2011 书生商友信息科技 All Right Reserved

24小时服务热线:400-111-6878   E-MAIL:1120768800@qq.com   QQ:1120768800

  网址: https://www.768800.com  网站建设上往建站

关键词: 网站建设| 域名邮箱| 服务器空间| 网站推广| 上往建站| 网站制作| 网站设计| 域名注册| 网络营销| 网站维护|

企业邮箱| 虚拟主机| 网络建站| 网站服务| 网页设计| 网店美工设计| 网站定制| 企业建站| 网站设计制作| 网页制作公司|

400电话办理| 书生商友软件| 葬花网| 调温纤维| 海洋馆运营维护| 北京保安公司| 殡仪馆服务| 殡葬服务| 昌平殡葬| 朝阳殡葬|

预约专家

欢迎您免费咨询,请填写以下信息,我们收到后会尽快与您联系

  

服务热线:400-111-6878