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网络面试题
3、说一下 Http 缓存策略,有什么区别,分别解决了什么问题
4、介绍防抖节流原理、区别以及应用,并用JavaScript进行实现
5、前端安全、中间人攻击
6、对闭包的看法,为什么要用闭包?说一下闭包原理以及应用场景
7、css 伪类与伪元素区别
8、数组遍历forEach、map、filter、find、some、every、reduce等区别
9、类数组和数组的区别,dom 的类数组如何转换成数组
10、webpack 做过哪些优化,开发效率方面、打包策略方面等等
build 时间: 102s
大小:
11、说一下事件循环机制(node、浏览器)
12、介绍下 promise 的特性、优缺点,内部是如何实现的,动手实现 Promise
13、实现 Promise.all
zhuanlan.zhihu.com/p/107712626
14、手写发布订阅
15、手写数组转树
16、process.nextTick()、setTimeout()、setInterval()
17、node中的setTimeout,setInterval,promise.then和process.nextTick()的执行顺序。
18、var min = Math.min(); max = Math.max(); console.log(min < max);
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。
最后就是再次渲染执行缓存和对应钩子函数了