errorCaptured三个钩子函数
发布时间:2025-06-24 20:01:22 作者:北方职教升学中心 阅读量:475
小米、
载入前/后:在 beforeMount 阶段,vue 实例的$el 和 data 都初始化了,但还是挂载之前为虚拟的 dom 节点,data.message 还未替换。
Vue.use(Vuex); // 1. vue的插件机制,安装vuex
let store = new Vuex.Store({ // 2.实例化store,调用install方法
state,
getters,
modules,
mutations,
actions,
plugins
});
new Vue({ // 3.注入store, 挂载vue实例
store,
render: h=>h(app)
}).$mount(‘#app’);
Vue.use是vue中的插件机制,内部会调用插件的install方法,vuex的install方法:
export function install (_Vue) {
if (Vue) {
if (process.env.NODE_ENV !== ‘production’) {
console.error(
‘[vuex] already installed. Vue.use(Vuex) should be called only once.’
)
}
return
}
/保存Vue,同时用于检测是否重复安装/
Vue = _Vue
/将vuexInit混淆进Vue的beforeCreate(Vue2.0)或_init方法(Vue1.0)/
applyMixin(Vue)
}
vuex是个全局的状态管理,全局有且只能有一个store实例,所以在install的时候会判断是否已经安装过了,这个就是单例模式,确保一个类只有一个实例。360、特别强调,项目经历不可忽视;几乎简历上提到的项目都会被刨根问底,所以项目应用的技术要熟练,底层原理必须清楚。
6. vuex 状态管理实现通信
vuex是专为vue设计的状态管理模式。
12.虚拟dom和diff算法
虚拟DOM是对DOM的描述,用对象属性来描述节点,本质上是JavaScript对象。
13.Vuex原理
vuex是什么,先看下官方的原话:
Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。destroyed
这两个钩子是vue实例销毁的钩子,定义在Vue.prototype.$destroy中:
Vue.prototype.$destroy = function () {
const vm: Component = this
if (vm._isBeingDestroyed) {
return
}
callHook(vm, ‘beforeDestroy’)
vm._isBeingDestroyed = true
// remove self from parent
const parent = vm.$parent
if (parent && !parent._isBeingDestroyed && !vm.$options.abstract) {
remove(parent.$children, vm)
}
// teardown watchers
if (vm._watcher) {
vm._watcher.teardown()
}
let i = vm._watchers.length
while (i–) {
vm._watchers[i].teardown()
}
// remove reference from data ob
// frozen object may not have observer.
if (vm._data.ob) {
vm._data.ob.vmCount–
}
// call the last hook…
vm._isDestroyed = true
// invoke destroy hooks on current rendered tree
vm.patch(vm._vnode, null)
// fire destroyed hook
callHook(vm, ‘destroyed’)
// turn off all instance listeners.
vm.$off()
// remove vuereference
if (vm.$el) {
vm.$el.vue= null
}
if (vm.$vnode) {
vm.$vnode.parent = null
}
}
}
在销毁之前执行callHook(vm, ‘beforeDestroy’),然后销毁的时候做了几件事:
如果有父元素,将父元素的$children中把该组件实例移除。并且通过remove(keys, key),将当前的key从keys中删除再重新keys.push(key),这样就改变了当前key在keys中的位置。mounted
3. beforeUpdate、看下callHook函数:
function callHook (vm: Component, hook: string) {
pushTarget()
const handlers = vm.$options[hook]
const info =
${hook} hook
if (handlers) {
for (let i = 0, j = handlers.length; i < j; i++) {
invokeWithErrorHandling(handlers[i], vm, null, vm, info)
}
}
if (vm._hasHookEvent) {
vm.$emit(‘hook:’ + hook)
}
popTarget()
}
接收一个vm组件实例的参数和hook,取组件实例的$options传入的hook属性值,有的话会循环调用这个钩子的回调函数。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化
这段话可以得出几个结论:Vuex是为vue.js服务的
,而像redux与react是解耦的,然后vuex是状态管理模式,所有的状态以一种可预测的方式发生变化。要注意的是官网有这一段话:
提示:provide 和 inject 绑定并不是可响应的。特别强调,项目经历不可忽视;几乎简历上提到的项目都会被刨根问底,所以项目应用的技术要熟练,底层原理必须清楚。接下来会将这个name通过include与exclude属性进行匹配,匹配不成功(说明不需要进行缓存)则不进行任何操作直接返回vnode
(vnode节点描述对象,vue通过vnode创建真实的DOM)
。包含了腾讯、搜狐等一线互联网公司面试被问到的题目,涵盖了初中级前端技术点。运行、实际上在很多高级组件中都可以看到组件会将this通过provide传递给子孙组件,包括element-ui、listeners
$attrs
: 包含了父作用域没被props声明
绑定的数据,组件可以通过v-bind="$attrs"
继续传给子组件
$listernes
: 包含了父作用域中的v-on
(不含 .native 修饰器的) 监听事件,可以通过v-on="$listeners"
传入内部组件5. provide、props等属性。涵盖HTML,CSS,JavaScript,HTTP,TCP协议,浏览器,Vue框架,算法等高频考点238道(含答案)!
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
资料截图 :
高级前端工程师必备资料包
const silent = Vue.config.silent
Vue.config.silent = true
store._vm = new Vue({
data: {
$$state: state
},
computed
})
Vue.config.silent = silent
// enable strict mode for new vm
if (store.strict) {
enableStrictMode(store)
}
if (oldVm) {
if (hot) {
// dispatch changes in all subscribed watchers
// to force getter re-evaluation for hot reloading.
store._withCommit(() => {
oldVm._data.$$state = null
})
}
Vue.nextTick(() => oldVm.$destroy())
}
}
resetStoreVM首先会遍历wrappedGetters,使用Object.defineProperty方法对store.getters的每一个getter定义get方法,这样访问this.$store.getter.test就等同于访问store._vm.test。
最后
=============================================================
在面试前花了三个月时间刷了很多大厂面试题,最近做了一个整理并分类,主要内容包括html,css,JavaScript,ES6,计算机网络,浏览器,工程化,模块化,Node.js,框架,数据结构,性能优化,项目等等。在挂载完成后监听include和exclude,动态地销毁已经不满足include的组件和满足exclude的组件实例:
created () {
this.cache = Object.create(null) // 存储需要缓存的组件
this.keys = [] // 存储每个需要缓存的组件的key,即对应this.cache对象中的键值
},
// 销毁keep-alive组件的时候,对缓存中的每个组件执行销毁
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函数:
render () {
const slot = this.$slots.default
const vnode: VNode = getFirstComponentChild(slot)
// 如果vnode存在就取vnode的选项
const componentOptions: VNodeComponentOptions = vnode && vnode.componentOptions
if (componentOptions) {
// check pattern
//获取第一个有效组件的name
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 // keep-alive组件的缓存组件和缓存组件对应的key
// 获取第一个有效组件的key
const key: string = vnode.key == null
// 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
// 更新当前key在keys中的位置
remove(keys, key)
keys.push(key)
} else {
cache[key] = vnode
keys.push(key)
// prune oldest entry
// 如果缓存中的组件个数超过传入的max,销毁缓存中的LRU组件
// LRU: least recently used 最近最少用,缓存淘汰策略
if (this.max && keys.length > parseInt(this.max)) {
pruneCacheEntry(cache, keys[0], keys, this._vnode)
}
}
vnode.data.keepAlive = true
}
// 若第一个有效的组件存在,但其componentOptions不存在,就返回这个组件进行渲染
// 或若也不存在有效的第一个组件,但keep-alive组件的默认插槽存在,就返回默认插槽的第一个组件进行渲染
return vnode || (slot && slot[0])
}
代码做了详细的注释,这里再分析下render做了什么。拼多多、滴滴、原生应用、
这里给大家提供一份汇集各大厂面试高频核心考点前端学习资料。编译模板、created:
Vue.prototype._init = function (options: Object) {
…
initLifecycle(vm)
initEvents(vm)
initRender(vm)
callHook(vm, ‘beforeCreate’)
initInjections(vm) // resolve injections before data/props
initState(vm)
initProvide(vm) // resolve provide after data/props
callHook(vm, ‘created’)
…
if (vm.$options.el) {
vm. m o u n t ( v m . mount(vm. mount(vm.options.el)
}
}
在执行beforeCreate之前调用了
initLifecycle、
所以Vue不会对provide中的变量进行响应式处理。
销毁前/后:在执行 destroy 方法后,对 data 的改变不会再触发周期函数,说明此时 vue 实例已经解除了事件监听以及和 dom 的绑定,但是 dom 结构依然存在
结合源码再理解,在源码中生命周期钩子是用callHook函数调用的。Redux,将数据存放到全局的store,再将store挂载到每个vue实例组件中,利用Vue.js的细粒度数据响应机制来进行高效的状态更新。
store实现的源码在src/store.js
,其中最核心的是响应式的实现,通过resetStoreVM(this, state)调用,看下这个方法:
function resetStoreVM (store, state, hot) {
const oldVm = store._vm
// bind store public getters
store.getters = {}
// reset local getters cache
store._makeLocalGettersCache = Object.create(null)
const wrappedGetters = store._wrappedGetters
const computed = {}
forEachValue(wrappedGetters, (fn, key) => {
// use computed to leverage its lazy-caching mechanism
// direct inline function use will lead to closure preserving oldVm.
// using partial to return function with only arguments preserved in closure environment.
computed[key] = partial(fn, store)
Object.defineProperty(store.getters, key, {
get: () => store._vm[key],
enumerable: true // for local getters
})
})
// use a Vue instance to store the state tree
// suppress warnings just in case the user has added
// some funky global mixins
const silent = Vue.config.silent
Vue.config.silent = true
store._vm = new Vue({
data: {
$$state: state
},
computed
})
Vue.config.silent = silent
// enable strict mode for new vm
if (store.strict) {
enableStrictMode(store)
}
if (oldVm) {
if (hot) {
// dispatch changes in all subscribed watchers
// to force getter re-evaluation for hot reloading.
store._withCommit(() => {
oldVm._data.$$state = null
})
}
Vue.nextTick(() => oldVm.$destroy())
}
}
resetStoreVM首先会遍历wrappedGetters,使用Object.defineProperty方法对store.getters的每一个getter定义get方法,这样访问this.$store.getter.test就等同于访问store._vm.test。要想 inject 接受的变量是响应式的,provide 提供的变量本身就需要是响应式的。
8.computed、字节跳动、
state是通过new一个Vue对象来实现数据的“响应式化”,运用Vue的data属性来实现数据与视图的同步更新,computed实现getters的计算属性。事件、
基本上可以说8 个阶段创建前/后,载入前/后,更新前/后,销毁前/后。
生命周期就是每个Vue实例完成初始化、inject
父组件通过provide注入一个依赖,其所有的子孙组件可以通过inject来接收。58、
看下组件更新的_update方法:
Vue.prototype._update = function (vnode: VNode, hydrating: boolean) {
const vm: Component = this
const prevEl = vm.$el
const prevVnode = vm._vnode
const restoreActiveInstance = setActiveInstance(vm)
vm._vnode = vnode
// Vue.prototype.patchis injected in entry points
// based on the rendering backend used.
if (!prevVnode) {
// initial render
vm.KaTeX parse error: Expected group after ‘_’ at position 9: el = vm.__patch__(vm.el, vnode, hydrating, false /* removeOnly */)
} else {
// updates
vm.$el = vm.patch(prevVnode, vnode)
}
}
…
vm.$el = vm._patch(),这个就是最终渲染的DOM元素,patch就是vue中diff算法的函数,在key的作用章节有提过。
diff算法发生在视图更新
的时候,也就是数据更新的时候,diff算法会将新旧虚拟DOM作对比,将变化的地方转换为DOM
。涵盖HTML,CSS,JavaScript,HTTP,TCP协议,浏览器,Vue框架,算法等高频考点238道(含答案)!
开源分享:【大厂前端面试题解析+核心总结学习笔记+真实项目实战+最新讲解视频】
资料截图 :
高级前端工程师必备资料包