2021

193 阅读6分钟

1、介绍chrome 浏览器的几个版本

Chrome 浏览器提供 4 种发布版本,即稳定版(Stable)、测试版(Beta)、开发者版(Dev)和金丝雀版(Canary)。

1.Canary(金丝雀) 版

  • 只限用于测试,Canary 是 Chrome 的未来版本,是功能、代码最先进的Chrome 版本,一方面软件本身没有足够时间测试,另一方面网页也不一定支持这些全新的功能,因此极不稳定。好在,谷歌将其设定为可独立安装、与其他版本的 Chrome 程序共存,因此适合进阶用户安装备用,尝鲜最新功能。这种不稳定性使得 Canary 版目前并不适合日常使用。
  • Chrome Canary 是更新速度最快的 Chrome 版本,几乎每天更新。它相当于支持自动更新、并添加了谷歌自家服务与商业闭源插件(Flash 等)的 Chromium,更加强大好用。

2.开发者版(Dev)

  • Chrome Dev 最初是以 Chromium 为基础、更新最快的 Chrome,后来则被 Canary 取代。Dev 版每周更新一次,虽然仍不太稳定,但已经可以勉强满足日常使用,适合 Web 开发者用来测试新功能和网页。
  • 让 IT 人员使用开发者版,开发者可以通过开发者版测试自己公司的应用,确保这些应用能与Chrome 最新的 API 更改及功能更改兼容。注意:开发者版并非百分之百稳定,但开发者可以提前 9 至 12 周体验即将添加到 Chrome 稳定版的功能。

3.测试版(Beta)

  • Chrome Beta 以 Dev 为基础,每月更新一次。它是正式发布前的最后测试版本,所有功能都已在前面几个版本中得到测试并改进,因此已经十分稳定,普通用户也可以用来日常使用
  • 让 5% 的用户使用测试版,测试版用户可以提前 4-6 周体验即将在 Chrome 稳定版中推出的功能。测试版用户可以发现特定版本可能存在的问题,让您可以先解决问题,然后再向所有用户推出该版本。

4.稳定版(Stable)

  • 最后的 Chrome Stable 就是我们熟知的正式版,它以 Beta 为基础,几个月更新一次。由于所有的功能都已经过数个月反复测试,是稳定性最高的 Chrome 版本。
  • 让大多数用户使用稳定版,稳定版是已进行充分测试的版本,稳定版每 2-3 周会进行一次小幅更新,并且每 6 周会进行一次重大更新。

2、HTTP网络面试题

www.yuque.com/u549385/nci…

3、说一下 Http 缓存策略,有什么区别,分别解决了什么问题

www.cnblogs.com/dennisj/p/1…

www.yuque.com/u549385/nci…

4、介绍防抖节流原理、区别以及应用,并用JavaScript进行实现

5、前端安全、中间人攻击

blog.csdn.net/SJ1551/arti…

6、对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景

www.cnblogs.com/wangyang021…

7、css 伪类与伪元素区别

zhuanlan.zhihu.com/p/46909886

8、数组遍历forEach、map、filter、find、some、every、reduce等区别

blog.csdn.net/RedaTao/art…

9、类数组和数组的区别,dom 的类数组如何转换成数组

blog.csdn.net/weixin\_441…

10、webpack 做过哪些优化,开发效率方面、打包策略方面等等

build 时间: 102s

大小:

blog.csdn.net/weixin\_338…

11、说一下事件循环机制(node、浏览器)

blog.csdn.net/weixin\_441…

12、介绍下 promise 的特性、优缺点,内部是如何实现的,动手实现 Promise

blog.csdn.net/weixin\_441…

blog.csdn.net/weixin\_561…

13、实现 Promise.all

zhuanlan.zhihu.com/p/107712626

14、手写发布订阅

blog.csdn.net/qq\_3995353…

15、手写数组转树

blog.csdn.net/erdfty/arti…

16、process.nextTick()、setTimeout()、setInterval()

blog.csdn.net/mo\_247/art…

17、node中的setTimeout,setInterval,promise.then和process.nextTick()的执行顺序。

blog.csdn.net/qq\_2209194…

18、var min = Math.min(); max = Math.max(); console.log(min < max);

zhuanlan.zhihu.com/p/22481953

19、 juejin.cn/post/684790…

20、blog.csdn.net/MFWSCQ/arti…

21、blog.csdn.net/MFWSCQ/arti…

22、blog.csdn.net/MFWSCQ/arti…

23、blog.csdn.net/MFWSCQ/arti…

24、Vue组件中写name选项有除了搭配keep-alive还有其他作用么?你能谈谈你对keep-alive了解么?(平时使用和源码实现方面)

答案

一、组件中写 name 选项有什么作用?
项目使用 keep-alive 时,可搭配组件 name 进行缓存过滤
DOM 做递归组件时需要调用自身 name
vue-devtools 调试工具里显示的组见名称是由vue中组件name决定的

二、keep-alive使用
keep-alive 是 Vue 内置的一个组件,可以使被包含的组件保留状态,避免重新渲染
一般结合路由和动态组件一起使用,用于缓存组件;
提供 include 和 exclude 属性,两者都支持字符串或正则表达式, include 表示只有名称匹配的组件会被缓存,exclude 表示任何名称匹配的组件都不会被缓存 ,其中 exclude 的优先级比 include 高;
对应两个钩子函数 activated 和 deactivated ,当组件被激活时,触发钩子函数 activated,当组件被移除时,触发钩子函数 deactivated。

三、keep-alive实现原理
1)首先看下源码

// 源码位置:src/core/components/keep-alive.js
export default {
  name: 'keep-alive',
  abstract: true, // 判断当前组件虚拟dom是否渲染成真是dom的关键

  props: {
    include: patternTypes, // 缓存白名单
    exclude: patternTypes, // 缓存黑名单
    max: [String, Number] // 缓存的组件实例数量上限
  },

  created () {
    this.cache = Object.create(null) // 缓存虚拟dom
    this.keys = [] // 缓存的虚拟dom的健集合
  },

  destroyed () {
    for (const key in this.cache) { // 删除所有的缓存
      pruneCacheEntry(this.cache, key, this.keys)
    }
  },

  mounted () {
    // 实时监听黑白名单的变动
    this.$watch('include', val => {
      pruneCache(this, name => matches(val, name))
    })
    this.$watch('exclude', val => {
      pruneCache(this, name => !matches(val, name))
    })
  },

  render () {
    // .....
  }
}

大概的分析源码,我们发现与我们定义组件的过程一样,先是设置组件名为keep-alive,其次定义了一个abstract属性,值为true。这个属性在vue的官方教程并未提及,其实是一个虚组件,后面渲染过程会利用这个属性。props属性定义了keep-alive组件支持的全部参数。

2)接下来重点就是keep-alive在它生命周期内定义了三个钩子函数了

created

初始化两个对象分别缓存VNode(虚拟DOM)和VNode对应的键集合

destroyed

删除缓存VNode还要对应执行组件实例的destory钩子函数。

删除this.cache中缓存的VNode实例。不是简单地将this.cache置为null,而是遍历调用pruneCacheEntry函数删除。

// src/core/components/keep-alive.js
function pruneCacheEntry (
  cache: VNodeCache,
  key: string,
  keys: Array<string>,
  current?: VNode
) {
  const cached = cache[key]
  if (cached && (!current || cached.tag !== current.tag)) {
    cached.componentInstance.$destroy() // 执行组件的destory钩子函数
  }
  cache[key] = null
  remove(keys, key)
}

mounted

在mounted这个钩子中对include和exclude参数进行监听,然后实时地更新(删除)this.cache对象数据。pruneCache函数的核心也是去调用pruneCacheEntry。

3)render

// src/core/components/keep-alive.js
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot) // 找到第一个子组件对象
const componentOptions: ?VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) { // 存在组件参数
    // check pattern
    const name: ?string = getComponentName(componentOptions) // 组件名
    const { include, exclude } = this
    if ( // 条件匹配
    // not included
    (include && (!name || !matches(include, name))) ||
    // excluded
    (exclude && name && matches(exclude, name))
    ) {
    return vnode
    }

    const { cache, keys } = this
    const key: ?string = vnode.key == null // 定义组件的缓存key
    // same constructor may get registered as different local components
    // so cid alone is not enough (#3269)
    ? componentOptions.Ctor.cid + (componentOptions.tag ? `::${componentOptions.tag}` : '')
    : vnode.key
    if (cache[key]) { // 已经缓存过该组件
    vnode.componentInstance = cache[key].componentInstance
    // make current key freshest
    remove(keys, key)
    keys.push(key) // 调整key排序
    } else {
    cache[key] = vnode // 缓存组件对象
    keys.push(key)
    // prune oldest entry
    if (this.max && keys.length > parseInt(this.max)) { 
        // 超过缓存数限制,将第一个删除(LRU缓存算法)
        pruneCacheEntry(cache, keys[0], keys, this._vnode)
    }
    }

    vnode.data.keepAlive = true // 渲染和执行被包裹组件的钩子函数需要用到
}
return vnode || (slot && slot[0])
}
  • 第一步:获取keep-alive包裹着的第一个子组件对象及其组件名;
  • 第二步:根据设定的黑白名单(如果有)进行条件匹配,决定是否缓存。不匹配,直接返回组件实例(VNode),否则执行第三步;
  • 第三步:根据组件ID和tag生成缓存Key,并在缓存对象中查找是否已缓存过该组件实例。如果存在,直接取出缓存值并更新该key在this.keys中的位置(更新key的位置是实现LRU置换策略的关键),否则执行第四步;
  • 第四步:在this.cache对象中存储该组件实例并保存key值,之后检查缓存的实例数量是否超过max的设置值,超过则根据LRU置换策略删除最近最久未使用的实例(即是下标为0的那个key)。
  • 第五步:最后并且很重要,将该组件实例的keepAlive属性值设置为true。

最后就是再次渲染执行缓存和对应钩子函数了

github.com/qappleh/Int…