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) 时;执行下面动作
- 执行了Vue.prototyoe._init方法
- meargeOptions 处理传入的options后赋值给vm.$options
- vm.$options:
- {
// Vue.options静态属性合并过来的
- components,
- filters,
- directives,
- _base,
// 传入的
- data(){},
- el,
// 暂时不确定
- render,
- staticRenderFns,
// 暂时不确定
- _parentElm,
- _refElm
}
- 执行initProxy添加 vm._render = vm // 开发环境里可能是一个代理对象
- 添加vm._self = vm ;然后执行initLifecycle,添加$parent,$children(数组),$refs({})
- 执行initEvents; 添加_events,_parentListeners(创建子组件实例才有这个文件)
- 执行initRender方法;添加$slots,$vnode,$scopeSlots三个属性
- 使用callHook调用beforeCreate钩子
- 依次实例化inject,porps,methods,data,computed,watch,provide
- 使用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 break case 'splice': inserted = args.slice(2) break } if (inserted) ob.observeArray(inserted) })
|
microtask(微任务) 与 macrotask (宏任务)
javascript 主线程有一个 执行栈 和 任务队列
- 按照顺序依次执行js代码,当遇到函数时,会先将函数入栈,等函数执行完将该函数出栈。
- 这个过程遇到setTimeout、ajax等异步任务时,该函数会立即返回一个值以免阻塞线程。同时将该任务的回调依次推入 任务队列,后续让浏览器执行。
- 执行完 执行栈的任务后,会按照先入先出原则,依次执行 任务队列里的回调函数
microtask 和 macrotask 都属于异步任务的一种
- microtask种类: process.nextTick、Promise、MutationObserver
- 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');
|
1 2 3 4
| 原因分析: 1. 异步任务分为 macrotask 和 microtask. 2. 每一次循环只取一个macrotask宏任务和当前栈中的所有微任务 3. 微任务先清空完才去执行宏任务
|