Original address Nuggets
Three consecutive oh more good articles github
Hello everyone, I am Lin Yiyi. This is an interview question about the principle of vue. If you can fully understand it, I believe it will be very helpful to everyone.
Interview questions
1. As the old saying goes, what are the advantages and disadvantages of the understanding of MPA/SPA?
MPA
multi-page application.
- Composition: There are multiple pages
html
composition, - Jump method: the page jump is from one page to another page
- Refresh mode: full page refresh
- Page data jump: rely on
URL/cookie/localStorage
- The redirected resource
will be reloaded
- Advantages: It is more friendly to SEO, and the development difficulty is lower.
SPA
Single page application
- Page composition: wrapped by a shell page, composed of multiple page (component) fragments
- Jump mode: Jump in the shell page, show or hide the fragment page (component)
- Refresh mode: partial refresh of page fragments
- Page data jump: it is easier to pass values between components
after the jump will not be reloaded
- Disadvantages: It is not very friendly to SEO search and needs to be configured separately, and the development is more difficult and requires a special development framework
The iframe is actuallyMPA
, but it can achieveSPA
, but it has many problems.
2. As the old saying goes, why do we need these MVC/MVVM patterns? Talk about the difference between your MVC and MVVM modes,
Purpose: To learn from the back-end ideas, responsibilities division and layering
- Vue, React is not really MVVM or MVC. Both cores only deal with the view layer
view
.
MVC mode
For one-way data, the user needs to re-request the database for each step of the operation to modify the rendering of the view layer, forming a one-way closed loop. For example, jQuery+underscore+backbone
.
- M:
model
data storage layer - V:
view
: View layer page - C:
controller
: Controller js logic layer.
controller
control layer processes the data of the data layermodel layer and displays it in the view layer
view layer. Similarly, the view layer
view layer can receive user instructions through the control layer
controller
and act on the data layermodel
. ThereforeMVC is that the view layer cannot directly interact with the data layer.
MVVM mode
Hiddencontroller
control layer, direct manipulationView
view layer andModel
data layer.
- M: model data model
- V: view template
- VM: view-model view data template (the layer processed by vue, the definedProperty in vue is the logic of processing the VM layer)
Two-way data binding:model
data model layer through data bindingData Bindings
directly affect the view layerView
, while the view layerview
by listeningDom Listener
can also change the data model layermodel
.
- Data binding and DOM event monitoring are the main things
viewModel
layerVue
That is to say: as long as thedata model layer Model is mounted to the
ViewModel
layerVue
, two-way data binding can be realized. - Plus
vuex/redux
can be used asvue and react
model
data layer.
var vm = new Vue()
vm is theview-model
data model layer, and data: is the dataview-model
- To sum up the difference between the two: MVC's view layer and data layer interaction needs to pass through the control layer
controller
is a one-way link. MVVM hides the control layercontroller
, so that the view layer and the data layer can directly interact, which is a two-way connection.
3. Talk about the understanding of reactive data in Vue
Small tip: Responsive data refers to data that has changed, and the view can be updated is responsive data
vue
implements adefinedReactive
method, internal methods borrowedObject.definedProperty()
to each attribute addedget/set
properties.definedReactive
can only monitor the outermost objects, and the inner objects need to recursively hijack data.- The array is rewritten 7
push pop shift unshift reverse sort splice
to intercept the data of the array, because these methods will change the original array - Expansion:
// src\core\observer\index.js
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
// 准备给属性添加一个 dep 来依赖收集 Watcher 用于更新视图。
const dep = new Dep()
// some code
// observe() 用来观察值的类型,如果是属性也是对象就递归,为每个属性都加上`get/set`
let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// 这里取数据时依赖收集
const value = getter ? getter.call(obj) : val
if (Dep.target) {
dep.depend()
// childOb 是对对像进行收集依赖
if (childOb) {
childOb.dep.depend()
//这里对数组和内部的数组进行递归收集依赖,这里数组的 key 和 value 都有dep。
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
// 属性发生改变,这里会通知 watcher 更新视图
}
})
}
What is the Dep (class) above? Answer: What isWatcher
andWatcher
used to collect and render? Answer:watcher
is a class used to update the view
4. How does Vue detect array changes?
definedProperty()
for data interception for each item in the array, but instead rewrites the arraypush pop shift unshift reverse sort splice
.- Manually call notify, notify render watcher, execute update
- If there are object types (
objects and arrays) in the array, data will be intercepted.
- Therefore, by modifying the array subscript and array length, data interception will not occur, and there will be no responsive changes. For example,
arr[0] = 1, arr.length = 2
will not be responsive - Expansion:
// src\core\observer\array.js
const methodsToPatch = ['push','pop','shift','unshift','splice','sort','reverse']
methodsToPatch.forEach(function (method) {
const original = arrayProto[method]
def(arrayMethods, method, function mutator (...args) {
const result = original.apply(this, args)
const ob = this.__ob__
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args
break
case 'splice':
inserted = args.slice(2)
break
}
// 新增的类型再次观察
if (inserted) ob.observeArray(inserted)
// 手动调用 notify 派发更新
ob.dep.notify()
return result
})
})
5. How does Vue rely on collection? (What is the relationship between dep and Watcher)
tip:Dep
is a class responsible for collectingWatcher
, andWatcher
is a class that encapsulates the rendering view logic and is used to distribute updates. It should be noted thatWatcher cannot directly update the view. It also needs to be combined with Vnode to pass the diff algorithm in patch() to generate the real DOM.
- Each attribute has its own
dep
attribute to store the dependentWatcher
. When the attribute changes, it will notifyWatcher
to update. - When the user obtains (
getter
) data, Vue adds thedep
attribute to each attribute to (collect as Dependency) to collectWatcher
. When the usersetting
sets the attribute value,dep.notify()
notifies the Watcher collected byre-render.
defineReactive()
above for details Dep dependent collection class It has a many-to-many two-way storage relationship
Watcher class
- Each attribute can have multiple
Watcher classes, because the attributes may be used in different components.
- At the same time, a
Watcher class can also correspond to multiple attributes.
6. Template compilation in Vue
<img src="https://p1-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/bc2f78cda8514103b4d0a29acb1a4c9a~tplv-k3u1fbpfcp-watermark.image" width="80%" height="360px"/>
Template compilation in Vue: In fact, it is to converttemplate
intorender
function. To put itis to compile the real 160aca788891f4 DOM (template) into a virtual
dom(Vnode)
- The first step is to convert the
template template string into
ast syntax tree (parser parser), where a large number of regulars are used to match tag names, attributes, texts, etc.
- The second step is to
static
of the AST, which is mainly used to optimize the rendering of the virtual DOM (optimize optimizer). Here, all the child nodes will be traversed and statically marked - The third step is to use the
ast syntax tree to regenerate the
render function code string code. (CodeGen code generator)
Why do you need to statically mark the node? If it is a static node (no data binding, no change before and after the node), then the subsequent diff algorithm is not needed for comparison.
7. The realization principle of life cycle hook
- The lifecycle hook in vue is just a callback function, and the corresponding hook is called to execute during the process of creating component instantiation.
- Use
Vue.mixin({})
mixed hooks or multiple functions defined in the life cycle, vue will callmergeHook()
to merge the hooks and put them in the queue for execution in sequence - Expand
// src\core\util\options.js
function mergeHook (
parentVal: ?Array<Function>,
childVal: ?Function | ?Array<Function>
): ?Array<Function> {
const res = childVal
? parentVal
? parentVal.concat(childVal) // 合并
: Array.isArray(childVal)
? childVal
: [childVal]
: parentVal
return res
? dedupeHooks(res)
: res
}
8. What are the commonplace vue life cycles, and where do I send requests?
beforeCreate
: Initialize the vue instance at the beginning, it is called before theobserver
, and the attributes such asdata/methods
created
: The initialization of the vue instance is over, and all the attributes have been created.beforeMount
: This hook is triggered before vue mounts the data to the page, and the render function is triggered at this time.mounted
: el isvm.$el
, the data initialized by vue has been mounted on the page, and the real DOM can be accessed here. Generally, data is requested here.beforeUpdate
: Called when the data is updated, that is, before the virtual dom is re-rendered.updated
: Data changes cause the virtual dom to be re-rendered.beforeDestroy
: This hook is called before the instance is destroyed, and the instance is still there.vm.$destroy
triggers two methods.destroyed
: Called after the Vue instance is destroyed. All event listeners will be touched.
Request data depends on specific business requirements to determine where to send ajax
9. Usage scenarios and principles of Vue.mixin(())
- Use scenario: Used to extract a common business logic to achieve reuse.
- Realization principle: calling
mergeOptions()
method adopts strategy mode to merge different attributes. If there is a conflict between the mixed data and the data of the component, the component itself is used. Vue.mixin({})
defects, 1. May cause naming conflicts between the mixed attribute name and the component attribute name; 2. The source of data dependence- Expand
export function mergeOptions (
parent: Object,
child: Object,
vm?: Component
): Object {
// some code
if (!child._base) {
if (child.extends) {
parent = mergeOptions(parent, child.extends, vm)
}
if (child.mixins) {
for (let i = 0, l = child.mixins.length; i < l; i++) {
parent = mergeOptions(parent, child.mixins[i], vm)
}
}
}
// 递归遍历合并组件和混入的属性
const options = {}
let key
for (key in parent) {
mergeField(key)
}
for (key in child) {
if (!hasOwn(parent, key)) {
mergeField(key)
}
}
function mergeField (key) {
const strat = strats[key] || defaultStrat
options[key] = strat(parent[key], child[key], vm, key)
}
return options
}
10. Why must the data in the vue component be a function?
- This is related to the mechanism of js itself
data
function is different, which can ensure that the data between different components does not pollute each other. Vue.mixin()
if mixeddata
attributes,data
must also be a function. BecauseVue.mixin()
can also be used in many places.- In the example,
data
can be an object or a function, because we generally only initialize one Vue instance (singleton) for a page
11. The realization principle and scenario of vm.$nextTick(cb) in vue
- Scenario:
called after the end of the dom update cycle to obtain the updated dom data
- Implementation principle:
vm.$nextTick(cb)
is an asynchronous method for compatibility with a lot of downgrade processing, followed bypromise.then,MutationObserver,setImmediate,setTimeout
. After modifying the data view is not immediately updated, but afterset
method of notification notifyWatcher
updates will need to update theWatcher
put into an asynchronous queue,nexTick
callback function to putWatcher
behind until the main thread synchronization code Execute the lodging and then clear the queue in turn, sovm.nextTick(callback)
is executed after the update ofdom
Watcher
in the above column invue asynchronous batch update. A little thought: Why not just use
setTimeout
instead? BecausesetTimeout
is a macro task, the performance of multiple macro tasks will be poor. About the event loop, you can look at JS event loop
12. The commonplace talk about the difference between watch and computed
computed
is implemented internally based onObject.definedProperty()
computed
cache function, and the dependent value will not be recalculated if it does not change.watch
is the monitoring value change, when the value changes, the corresponding callback function will be executed.computed
andwatch
are implemented based on theWatcher class.
computed
caching feature relies on a variabledirty
, represents the default value is not dirty istrue
, the value isfalse
, when the value againdirty
orfalse
directly or return to previous values.
// src\core\instance\state.js computed 取值函数
function createComputedGetter (key) {
return function computedGetter () {
const watcher = this._computedWatchers && this._computedWatchers[key]
if (watcher) {
if (watcher.dirty) { // 判断值是不是脏 dirty
watcher.evaluate()
}
if (Dep.target) {
watcher.depend()
}
return watcher.value
}
}
}
// src\core\instance\state.js watch 实现
Vue.prototype.$watch = function (
expOrFn: string | Function,
cb: any,
options?: Object
): Function {
const vm: Component = this
if (isPlainObject(cb)) {
return createWatcher(vm, expOrFn, cb, options)
}
options = options || {}
options.user = true
// 实例化 watcher
const watcher = new Watcher(vm, expOrFn, cb, options)
if (options.immediate) {
const info = `callback for immediate watcher "${watcher.expression}"`
pushTarget()
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info)
popTarget()
}
return function unwatchFn () {
watcher.teardown()
}
}
reference
Vue template compilation principle
the end
Thank you everyone for reading here. If you think the writing is okay, welcome Sanlian, I am Lin Yiyi, see you next time.
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。