vue源码学习之旅-day5

new Vue({}) 过程梳理

part 3

1
2
3
4
5
6
7
8
9
1. new Vue 说明Vue是一个构造函数。
2. 搜索export default Vue,找到core/instance/index.js
3. 发现执行了this._init方法
4. 依次执行了initMixin、stateMixin、renderMixin、eventsMixin、lifecycleMixin、warn函数为入参Vue构造函数添加了相关原型方法
5. 先看initMixin;添加了_init方法
6. 再看stateMixin; 添加了$data和$props两个只读属性到实例上;添加了$del,$set,$watch方法
7. renderMixin; 添加了$nextTick , _render方法
8. eventMixin;添加了$on $once $emit $off 方法
9. lifecycleMixin;添加了 _update,$foreceUpdate,$destory
1
2
3
4
5
6
7
8
9
const vm = new Vue({
data:function (){
return {
a:1
}
}
})

vm.a = 2

分析: new Vue(options) 时;执行下面动作

    1. 执行了Vue.prototyoe._init方法
    1. meargeOptions 处理传入的options后赋值给vm.$options
    1. vm.$options:
    • {
      // Vue.options静态属性合并过来的
      • components,
      • filters,
      • directives,
      • _base,
        // 传入的
      • data(){},
      • el,
        // 暂时不确定
      • render,
      • staticRenderFns,
        // 暂时不确定
      • _parentElm,
      • _refElm
        }
    1. 执行initProxy添加 vm._render = vm // 开发环境里可能是一个代理对象
    1. 添加vm._self = vm ;然后执行initLifecycle,添加$parent,$children(数组),$refs({})
    1. 执行initEvents; 添加_events,_parentListeners(创建子组件实例才有这个文件)
    1. 执行initRender方法;添加$slots,$vnode,$scopeSlots三个属性
    1. 使用callHook调用beforeCreate钩子
    1. 依次实例化inject,porps,methods,data,computed,watch,provide
    1. 使用callHook调用created钩子

数组对象相关方法拦截的实现原理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
	1.Array.proptotype为原型创建一个对象
2. 缓存原有数组方法
3. 通过Object.defineProperty拦截数组相关方法,并且定义重名方法来改写他
4. def(arrayMethods, method, function mutator (...args) {
// 省略...
let inserted
switch (method) {
case 'push':
case 'unshift':
inserted = args // push unshift 参数就是新增的参数
break
case 'splice':
inserted = args.slice(2) // splice第2个参数后面都是新增变量。所以直接截取
break
}
if (inserted) ob.observeArray(inserted)
// 省略...
})

microtask(微任务) 与 macrotask (宏任务)

javascript 主线程有一个 执行栈 和 任务队列

    1. 按照顺序依次执行js代码,当遇到函数时,会先将函数入栈,等函数执行完将该函数出栈。
    1. 这个过程遇到setTimeout、ajax等异步任务时,该函数会立即返回一个值以免阻塞线程。同时将该任务的回调依次推入 任务队列,后续让浏览器执行。
    1. 执行完 执行栈的任务后,会按照先入先出原则,依次执行 任务队列里的回调函数

microtask 和 macrotask 都属于异步任务的一种

    1. microtask种类: process.nextTick、Promise、MutationObserver
    1. macrotask种类:setTimeout、setInterval、setImmediate,I/O,UI rendering
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
console.log('script start');
setTimeout(function() {
console.log('setTimeout');
}, 0);
Promise.resolve().then(function() {
console.log('promise1');
}).then(function() {
console.log('promise2');
});
console.log('script end');

// script start
// script end
// promise1
// promise2
// setTimeout
1
2
3
4
原因分析:
1. 异步任务分为 macrotask 和 microtask.
2. 每一次循环只取一个macrotask宏任务和当前栈中的所有微任务
3. 微任务先清空完才去执行宏任务