0%

原文链接 https://juejin.im/post/5d8cc378f265da5ba0776f36

前言

前端页面性能是一个非常核心的用户体验指标。本文介绍阿里 UC 岳鹰全景监控平台 如何设计一个通用、低侵入性、自动上报的页面性能监控方案。主要采用的是 Navigation Timing API 以及 sendBeacon 等方法。

导读

为什么要监控页面性能

阅读全文 »

原文链接:https://juejin.im/post/5e6a1f406fb9a07cae13781e

数据类型与内存

数据类型分类

主要分为两大类:基本数据类型、复杂数据类型,详细分类如下。

  • 基本数据类型: String、Number、Boolean、Null、Undefined、Symbol
  • 复杂数据类型: Object 以及所有继承自 Object 的类型
阅读全文 »

上两章分析了 Vueupdate 阶段,本章我们以点击 点击让第二个App组件卸载 触发 hide 执行 this.isShow = false 为例,分析 Vuedestroyed 阶段。

前面逻辑同 update 阶段一致,触发该属性的订阅即 渲染 watcher 执行 run 方法,在 updateComponent 里先执行 vm._render 得到最新 vnode,然后执行 vm._update 更新 dom

updateChildren 循环里遍历比较子 vnode,可以看出只有最后一个 vnode 不同:旧 vnodeApp 组件 vnode,新 vnode 为注释 vnode。 则先调用 createElm 根据注释 vnode 创建真实 dom 并插入到对应位置;然后在 while 下次循环时,对旧的 App 组件 vnode 执行 removeVnodes 移除。

removeVnodes

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
function removeVnodes(vnodes, startIdx, endIdx) {
for (; startIdx <= endIdx; ++startIdx) {
var ch = vnodes[startIdx];

if (isDef(ch)) {
if (isDef(ch.tag)) {
removeAndInvokeRemoveHook(ch);
invokeDestroyHook(ch);
} else {
// Text node
removeNode(ch.elm);
}
}
}
}
阅读全文 »

接上文,得到 vnode 后执行 vm._update。因为 vm._vnode 存在即已经渲染过,则走更新方法:

1
2
// updates
vm.$el = vm.__patch__(prevVnode, vnode);

vm.__patch__patch 方法,进入 patch 流程。

sameVnode

1
2
3
4
5
6
7
function sameVnode(a, b) {
return (
a.key === b.key &&
((a.tag === b.tag && a.isComment === b.isComment && isDef(a.data) === isDef(b.data) && sameInputType(a, b)) ||
(isTrue(a.isAsyncPlaceholder) && a.asyncFactory === b.asyncFactory && isUndef(b.asyncFactory.error)))
);
}
阅读全文 »

前面七章分析了 vue demo 的整个初始化过程,本文开始分析当数据(model)发生变化时,Vue 的处理过程。

我们以点击 dom 触发 plus 执行 this.info.age++ 为例,分析 Vueupdate 阶段。

proxyGetter && proxySetter

此时读取 this.info,则触发在 ininState->initData->proxy(vm, "_data", key) 监听的 proxyGetter:

1
2
3
4
5
6
7
8
9
10
11
function proxy(target, sourceKey, key) {
sharedPropertyDefinition.get = function proxyGetter() {
return this[sourceKey][key];
};

sharedPropertyDefinition.set = function proxySetter(val) {
this[sourceKey][key] = val;
};

Object.defineProperty(target, key, sharedPropertyDefinition);
}
阅读全文 »

vnode 渲染为真实 dom

接上文,vm._render 通过 render 生成 vnode 后,然后执行 vm._update(vm._render(),hydrating) 来首次渲染成真实 dom,里面执行:

1
2
3
4
5
6
7
if (!prevVnode) {
// initial render
vm.$el = vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */);
} else {
// updates
vm.$el = vm.__patch__(prevVnode, vnode);
}

此处为初始渲染,执行第一个分支 vm.__patch__(vm.$el, vnode, hydrating, false /* removeOnly */); 即执行 patch

patch 中因为 oldVnodevm.$el 是真实节点,则 oldVnode 替换为空 vnode,然后执行:

阅读全文 »

接上文,在触发生命周期钩子 created 后,执行:

1
2
3
if (vm.$options.el) {
vm.$mount(vm.$options.el);
}

该句执行完后,_init 方法(位置在 src/core/instance/init.js)执行结束。

$mount 简述

判断是否有 $options.el,如果有就直接执行:vm.$mount(vm.$options.el)。在前面已经提到 $mount 方法与平台相关,所以在本例会执行 entry-runtime-with-compiler.js 中的 $mount

阅读全文 »

接上文继续分析,在触发生命周期钩子 beforeCreate 后,执行:

1
2
3
4
initInjections(vm); // resolve injections before data/props
initState(vm);
initProvide(vm); // resolve provide after data/props
callHook(vm, 'created');

initInjections

依赖注入,用于层级组件间传值,不可响应。

判断是否存在 $options.inject,然后在 resolveInject 里递归向上各级父元素中查找 vm._provided 属性值里是否有对应的注入值。找到最新值后放在实例下监听, set 方法设置无法重写,即不能更改注入值。

阅读全文 »

根据 demo 配置,将 demo 跑起来,然后忽略掉分支剧情,只分析 Vue 运行的主流程。

引入 Vue 和 App

执行 index.js, 先执行:

1
2
import Vue from 'vue';
import App from './app.vue';
  • 变量 VueVue 的构造函数,在执行 Vue 文件的过程中,会初始化设置 Vue 上的原型变量方法,Watch 类,Dep 类等等。
  • 变量 App 为经过 webpack 编译,通过 vue-loader,vue-template-compiler,VueLoaderPlugin 作用后的包含 renderstaticRenderFns组件选项对象:
阅读全文 »