vue源码解析之--核心部分core-util(二)

前言

 在vue源码目录中有个core文件夹,其核心功能比如组件、数据绑定、虚拟dom等等都在里面。core下面又分为了components、global-api、instance、obsever、util、vdom六个部分,这次还是先以util开头,里面也封装了一些工具型的函数并且引用了外层share里面的工具函数。

debug.js error.js

 debug.js里面主要封装的是用于开发阶段的调试相关的方法,比如一些提示警告。error.js里面只封装了一个handleError方法,用于处理错误,可在config里设置专门的errorHandler函数,没有的时候就只是一个warn警告。debug.js里面有一个repeat方法,将传入字符串重复N次。

var repeat = function (str, n) {
  var res = '';
  while (n) {
    if (n % 2 === 1) {
      res += str;
    }
    if (n > 1) {
      str += str;
    }
    n >>= 1;
  }
  return res
};


这样写的时间复杂度大概是二分之一N,lodash里也有相似的方法,不过是用Math.round(n/2)来代替n>>=1,n>>=1就是把N转换成二进制,然后右移一位再首位补0.

env.js

 env.js主要是一些环境相关的东西,待会儿重点说的是nextTick方法。
var inBrowser = typeof window !== ‘undefined’
是否在浏览器中,只要判断window对象是否存在即可。
var UA = inBrowser && window.navigator.userAgent.toLowerCase();

浏览器中通过userAgent,判断浏览器的版本内核。

​
function nextTickHandler() {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copiesi
  }
}
// pending是一个标示符, 用于确保timerFunc方法不会被重复调用。 接下来是根据浏览器支持情况来定义timeFunc方法:
if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => {
    console.error(err)
  }
  timerFunc = () => {
    p.then(nextTickHandler).catch(logError)
    if (isIOS) setTimeout(noop)
  }
}

​


isNative 判断某些方法功能是否原生支持的,比如浏览器支持symbol的话,symbol.tostring就会返回function Symbol() { [native code] },再用正则表达式判断是否包含native code即可。
 下面讲一下nextTick方法,这个方法也比较常用,可以在确定数据改变视图改变后再执行某些动作。代码首先定义一个自执行匿名函数的作用域,然后定义了一个nextTickHandler函数用于执行完成异步后需要执行的函数。

​
function nextTickHandler() {
  pending = false
  const copies = callbacks.slice(0)
  callbacks.length = 0
  for (let i = 0; i < copies.length; i++) {
    copiesi
  }
}

​


pending是一个标示符,用于确保timerFunc方法不会被重复调用。接下来是根据浏览器支持情况来定义timeFunc方法:

if (typeof Promise !== 'undefined' && isNative(Promise)) {
  var p = Promise.resolve()
  var logError = err => {
    console.error(err)
  }
  timerFunc = () => {
    p.then(nextTickHandler).catch(logError)
    if (isIOS) setTimeout(noop)
  }
}


如果浏览器支持promise,就用promise.then来定义timerFunc,promise的具体用法这里也不多讲了,然后我看源码上的注释是说:promise.then执行的时间可能不稳定,当他被推入一个微任务队列中时,添加一个空的setTimeout可以强制刷新微任务队列(IOS系统中).

else if (typeof MutationObserver !== 'undefined' && (
    isNative(MutationObserver) ||
    // PhantomJS and iOS 7.x
    MutationObserver.toString() === '[object MutationObserverConstructor]'
  )) {
  // use MutationObserver where native Promise is not available,
  // e.g. PhantomJS IE11, iOS7, Android 4.4
  var counter = 1
  var observer = new MutationObserver(nextTickHandler)
  var textNode = document.createTextNode(String(counter))
  observer.observe(textNode, {
    characterData: true
  })
  timerFunc = () => {
    counter = (counter + 1) % 2
    textNode.data = String(counter)
  }
}


当promise不被支持,但浏览器支持MutationObserver时。MutationObserver是html5的一个新特性,用于监测dom节点变化。初始化一个MutationObserver的实例observer ,传入的nextTickHandler是作为监测到发生变化后执行的回调函数,然后这里新建一个文本节点,再使用observer .observe()方法将文本节点绑定监听。最后定义的timerFunc就是改变文本节点的值,从而触发回调,这个回调是在文本节点重新渲染后执行的。当以上两个方法都不支持时,就只好用setTImeout来定义timerFunc了。

return function queueNextTick(cb ? : Function, ctx ? : Object) {
  let _resolve
  callbacks.push(() => {
    if (cb) {
      try {
        cb.call(ctx)
      } catch (e) {
        handleError(e, ctx, 'nextTick')
      }
    } else if (_resolve) {
      _resolve(ctx)
    }
  })
  if (!pending) {
    pending = true
    timerFunc()
  }
  if (!cb && typeof Promise !== 'undefined') {
    return new Promise((resolve, reject) => {
      _resolve = resolve
    })
  }
}


最后返回的函数其实就是nextTick自身,传入两个参数,一个是异步回调执行的函数,第二个是一个对象作为执行的环境。将传入的函数以 cb.call(ctx)的形式添加到callback中,然后再执行timerFunc。在global.api中,将这里定义的nextTick放在vue的原型上了。
env.js在最后定义了_Set,如果支持set那么就直接用set了,不支持的话,定义了一个_set类,并为其添加has()、add()、clear()方法。其实set的用法也比较简单,浏览器不支持的话自己重新定义一下也不复杂。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值