Vue2 时序图-待完善

305 阅读1分钟
sequenceDiagram
constructor->>+_init:new Vue({})
_init->>_init:this._uid++
_init->>_init:this._isVue=true
_init->>_init:mergeOptions(staticOptions,options,this)
_init->>+initLifecycle:初始化父子关系
initLifecycle->>initLifecycle:找妈妈(!parent.$options.abstract) ,parent.$children.push(this),this.$parent=parent
initLifecycle->>initLifecycle:this.$root=parent&&parent.$root||this
initLifecycle->>-_init:初始化父子关系 end
_init->>+initEvents:设置父组件添加在自身的监听:@customEvent
initEvents->>initEvents:listeners = vm.$options._parentListeners
initEvents->>initEvents:updateListeners:this['$on'|'$off']('customeEvent')
initEvents->>-_init:初始化监听 end
_init->>+initRender:初始化渲染函数
initRender->>initRender:this._vnode=null
initRender->>initRender:this._vnode=this.options._parentVnode
initRender->>initRender:this.$slots=resolveSlots(options._renderChildren,parentVnode&&parentVnode.context)
initRender->>initRender:this._c=createElement
initRender->>initRender:defineReactive(this,"$attrs",parentVnode.data.attr)
initRender->>initRender:defineReactive(this,"$listeners",options._parentListeners)
initRender->>-_init:_init
_init->>_init:callHook beforeCreate
_init->>+initInjections:initInjections
initInjections->>-_init:initInjections end
_init->>+initState:initState
initState->>initState:initProps
initState->>initState:initMethods:this[key]=bind(options.methods[key],this)
initState->>initState:initData:observer(options.data)
initState->>initState:initComputed:computed里面的方法会被包装成一个watcher,然后将watcher的Deps向上传递给render的watcher
initState->>initState:initWatch
initState->>-_init:initState end
_init->>+initProvider:initProvider
initProvider->>-_init:initProvider end
_init->>_init:invoke created hook
_init->>_init:invoke created hook
alt this.options.el
	_init->>+mount:this.$mount:如果options里面有el配置,则直接挂载到el上;不然需要手动调用new Vue({}).mount("#app")
	mount->-_init:mount end
end
_init-->-constructor:constructor
sequenceDiagram
    mount->+compileToFunctions:编译模版为render函数
    compileToFunctions->>compileToFunctions:compileOption.directives.push[v-model]:预处理input,select上面的v-model属性,component上面的v-model会被处理成el.model={value,exp,cb}
    compileToFunctions->>compileToFunctions:compileOption.directives.push[v-html]
    compileToFunctions->>compileToFunctions:compileOption.directives.push[v-text]
    compileToFunctions->>compileToFunctions:compileOption.modules.push[style{transformNode,genData}]
    compileToFunctions->>compileToFunctions:compileOption.modules.push[module{preTransformNode}]
    compileToFunctions->>compileToFunctions:compileOption.modules.push[class{transformNode,genData}]
    compileToFunctions->+parse:解析template,获取ast语法树
    parse->>+parseElementStart:检测到element开始标记:收集attrs,创建element实例
    parseElementStart->>parseElementStart:createASTElement(tag,arrts,parent)
    parseElementStart->>parseElementStart:invoke preTransfromNode
    parseElementStart->>parseElementStart:el.pre='v-pre' in attrs
    parseElementStart->>parseElementStart:processFor
    parseElementStart->>parseElementStart:processIf
    parseElementStart->>parseElementStart:processOnce
    parseElementStart->>-parse:end    
    parse->>+parseElementEnd:检测到element结束标记,进一步处理element属性,绑定父子关系
    parseElementEnd->>parseElementEnd:processKey:el.key=exp
    parseElementEnd->>parseElementEnd:processRef:el.ref=exp,el.refInFor=element in for
    parseElementEnd->>parseElementEnd:processSlotContent:el.slotTarget=name,el.slotTargetDynamic=boolean,el.slotScope=attrValue||"_empty_"
    parseElementEnd->>parseElementEnd:processSlotOutlet:el.slotName=attrs['name']//<slot name='header'/>
    parseElementEnd->>parseElementEnd:processComponenet:el.component=attrs['is']
    parseElementEnd->>parseElementEnd:invoke transformNode
    parseElementEnd->>+processAttrs:开始处理自定义绑定数据/指令
    processAttrs->>processAttrs:el.hasBinding=boolean
    processAttrs->>processAttrs:处理v-bind:xxx.sync="yyy": 添加监听el['event'/'nativeEvent']['update:xxx'],添加属性el.props.push({name,value,dynamic})
    processAttrs->>processAttrs:处理v-on:添加监听el['event'/'nativeEvent']['update:xxx']
    processAttrs->>processAttrs:处理v-xxx自定义指令:el.directives.push({name,value,arg,...})
    processAttrs->>processAttrs:处理一般属性(eg:id="xx"):el.attrs.push({name,value})
    processAttrs->>-parseElementEnd:end
    parseElementEnd->>parseElementEnd:parent.scopedSlots[element.slotScope||'default']=element//这里的parent必然是个vue component
    parseElementEnd->>parseElementEnd:invoke postTransfromNode
    parseElementEnd->>-parse:解析html完成,返回ast tree
    parse->>-compileToFunctions:end
    compileToFunctions->>+generate:从ast语法树生成render函数
    generate->>+genElement:genElement
    genElement->>genElement:genStatic
    genElement->>genElement:genOnce
    genElement->>genElement:genFor
    genElement->>genElement:genIf
    genElement->>genElement:genChildren:针对template
    genElement->>genElement:genSlot
    genElement->>genElement:genElement/genComponent/genChildren:后序遍历
    genElement->>genElement:invoke options.modules.codeTransform    
    genElement->>+genData:genData
    genData->>genData:data.directives
		genData->>genData:data.key
    genData->>genData:data.ref
    genData->>genData:data.refInFor=boolean
    genData->>genData:data.pre=boolean
    genData->>genData:data.tag=el.component?el.tag:''
    genData->>genData:invoke options.modules.genData
    genData->>genData:data.attrs={genProps(el.attrs)}
    genData->>genData:data.domProps={genProps(el.props)}
    genData->>genData:data.on = {"click":()=>{}}
    genData->>genData:data.nativeOn
    genData->>genData:data.slot
    genData->>genData:data.scopedSlots
    genData->>genData:data.model
    genData->>genData:data.inlineTemplate
    genData->>-genElement:genData end
    genElement->>-generate:genElement end
    generate->>-compileToFunctions:render 函数体字符串
    compileToFunctions->-mount:mount
sequenceDiagram
mount->>compileToFUnctions:编译模版为render函数
compileToFUnctions->>mount:返回render函数
mount->>mount:this.options.render=render
mount->>+mountComponent:mountComponent
mountComponent->>mountComponent:callHook beforeMount
mountComponent->>+RenderWatcher:创建负责响应渲染的watcher
RenderWatcher->>RenderWatcher:new Watcher(this,exp=()=>{this._update(this._render(),hydrating)},cb=noop,{before(){//invoke beforeupdate hook}})
RenderWatcher->>RenderWatcher:this.lazy=false
RenderWatcher->>+RenderWatcher:this.get//因为this.lazy=false,watcher创建后会立刻执行get方法
RenderWatcher->>RenderWatcher:pushTarget(this)
RenderWatcher->>RenderWatcher:this.exp()//vm._update
RenderWatcher->>+_render:vm._render
_render->>+_render:createElement:创建VNode
_render->>+data:访问data,读取data的值
alt data from this.data
data->>+reactiveGetter:get data
reactiveGetter->>reactiveGetter:Dep.target.dep(reactiveData),reactiveData.sub(Dep.target)
reactiveGetter->>-data:return value
else data from this.props
data->>+reactiveGetter:get props
reactiveGetter->>reactiveGetter:data.get,Dep.target.dep(reactiveData),reactiveData.sub(Dep.target),但props里面的属性值只建议在父组件更改
reactiveGetter->>-data:return value
else data from this.computed
data->>+computedGetter:获取computed值
computedGetter->>computedGetter:watcher=this._computedWatchers[key]
  alt watcher is dirty
  computedGetter->>computedGetter:computed属性的代理
  computedGetter->>+watcher:watcher.evaluate,
  watcher->>watcher:watcher.get
  watcher->>watcher:pushTarget(this)
  watcher->>+computeFn:watcher.exp()//对应的compute方法
  computeFn->>+reactiveGetter:访问相关的data,
  reactiveGetter->>reactiveGetter:依赖收集:Dep.target.dep(reactiveData),reactiveData.sub(Dep.target)
  reactiveGetter->>-computeFn:return value
  computeFn->>-watcher:watcher.exp() end//对应的compute方法
  watcher->>watcher:popTarget(this)
  watcher->>-computedGetter:watcher.dirty=false,return value
  end
computedGetter->>+watcher:watcher.depend:将此watcher 订阅的 dep 传递给前一个watcher(redner watcher or other computed watcher)
watcher->>RenderWatcher:我的奴隶就是你的奴隶
RenderWatcher->>watcher:好的儿子
watcher->>-computedGetter:done
computedGetter->>-data:return watcher.value
end
data->>-_render:return value
_render->>-_render:createElement:返回VNode
_render->>-RenderWatcher:vm._render end
RenderWatcher->>+_update:更新VNode为Dom,并挂载到节点上
_update->>-RenderWatcher:vm._update end
RenderWatcher->>RenderWatcher:popTarget
RenderWatcher->>-RenderWatcher:渲染完毕
RenderWatcher->>-mountComponent:初始化完毕
alt vm.node
mountComponent->>mountComponent:call hook mounted
end
mountComponent->>-mount:return vm
sequenceDiagram
_render->>+createElement:执行编译期间生成的fn,生成VNode
createElement->>createElement:tag=data.is || tag:处理动态component
alt typeof tag === 'string'
  alt tag is htmlTag
	createElement->>createElement:vnode=new VNode(htmlTag,data,children,vm)
	else tag is Component 
	createElement->>+createComponent:vnode=createComponent(Ctor,data,childern,vm)
		alt
			createComponent->>createComponent:尝试处理异步组件
		end
	createComponent->>createComponent:transfromVModel:data.on[event]=cb,data.attr[prop]=value
	createComponent->>createComponent:propsData=extractPropsFromVNodeData(data,Ctor,tag):将自组件定义的props中的属性拎出来
    alt Ctor.options.functional
    createComponent->>createComponent:createFunctionalComponent:处理方法组件
    end
  createComponent->>createComponent:listeners=data.on:这些都是父组件的监听
  createComponent->>createComponent:data.on=data.nativeOn:这些才是子组件需要处理的监听(监听对象在子组件的vnode上)
  createComponent->>createComponent:data.hook=installComponentHooks():合并hooks,监听vnode的生命周期
	createComponent->>-createElement:return new VNode(Ctor string,data,ctx=vm,cmpOpt={Ctor,propsData,listeners,tag,children},asyncFactory),创建compoent vnode,placeHolder vnode
	else default
	createElement->>createElement:vnode=new VNode(tag,data,children,vm)
	end
else default tag就是component的Ctor
createElement->>createElement:vnode=new createComponent(Ctor,data,children,vm)
end
createElement->>-_render:return VNode||VNode[]
sequenceDiagram
_update->>+_update:vm._update(vnode,hydrating)根据地vnode的变化更新dom
_update->>_update:preVnode=vm._vnode,vm._vnode=vnode
alt preVnode==null
_update->>+__patch__:vm.$el=vm.__patch__(vm.$el,vnode,hydrating,false)挂载
else
_update->>+__patch__:vm.$el=vm.__patch__(preVnode,vnode)更新
end
__patch__->>__patch__:添加平台相关的dom操作dom创建,查找:nodeOps={document.createElement...}
__patch__->>__patch__:添加基本的node扩展vue功能扩展:modules.add({v-directive,ref})
__patch__->>__patch__:添加平台相关的node扩展dom属性操作:modules.add({event,attrs,class,transition,style,domProps})
__patch__->>__patch__:格式化扩展按照生命周期分组:cb = {'create', 'activate', 'update', 'remove'}, 'destroy'
alt 新节点是空的 
	alt 旧节点不存在: 删除操作
    __patch__->>+invokeDestroyHook:invokeDestroyHook(oldVnode)
    invokeDestroyHook->>invokeDestroyHook:data.hook.destory()
    invokeDestroyHook->>invokeDestroyHook:cb.desctory()
    invokeDestroyHook->>invokeDestroyHook:invokeDestroyHook(node.children)递归孩子
    invokeDestroyHook->>-__patch__:patch结束
  end
else 新节点不为空
	alt 旧节点是空的
		__patch__->>__patch__:empty mount
	else 旧节点存在
		alt 旧节点是dom节点
			__patch__->>+createElm:oldVNode=emptyVNode(oldVNode):初次挂载VNode
		else 旧vnode不是dom节点
			alt 新旧vnode相同
			__patch__->>+patchVNode:更新操作
			else 新旧vnode不相同
			__patch__->>+createElm:createElm(vnode,insertQueue,parentElm,nextSibling):创建新的dom节点替换现有的节点
			__patch__->>__patch__:cb.remove:移除掉旧的dom节点
			__patch__->>__patch__:vnode.data.remove:移除掉旧的dom节点
			__patch__->>__patch__:cb.desctory:vnode销毁
			__patch__->>__patch__:vnode.data.desctory:vnode销毁
			end
		end
	end
end
alt vnode.tag is component
	createElm->>+createComponent:createComponent
	createComponent->>createComponent:invoke vnode.data.hook.init
	createComponent->>+componentVNodeHooks.init:创建component
	alt vnode.componentInstance&&!vnode.componentInstance._isDestoryed && vnode.data.keepAlive
		componentVNodeHooks.init->>+componentVNodeHooks.prepatch:旧的componet实例componentVNodeHooks.prepatch(mountedNode, mountedNode)
		componentVNodeHooks.prepatch->>+updateChildComponent:updateChildComponent
		updateChildComponent->>updateChildComponent:diff
		updateChildComponent->>+patchVnode:更新vnode
		updateChildComponent->>updateChildComponent:invoke vnode.options.data.hooks.prepatch
		alt vnode 是vm
		updateChildComponent->>+prepatch:更新vm
		prepatch->>prepatch:child=vnode.componentInstance=oldVNode.componentInstance
		prepatch->>+updateChildComponent:更新子vm
		updateChildComponent->>updateChildComponent:更新props,listeners,attrs,
		alt vm has slots children
		updateChildComponent->>updateChildComponent:forceupdate
		end
		updateChildComponent->>-prepatch:更新子vm结束
		prepatch->>-updateChildComponent:更新vm完毕
		end
		updateChildComponent->>updateChildComponent:invoke cbs.update
		updateChildComponent->>updateChildComponent:invoke vnode.options.hooks.update
		updateChildComponent->>updateChildComponent:invoke vnode.options.hooks.postpatch
		patchVnode->>-updateChildComponent:更新vnode完毕
		updateChildComponent->>-componentVNodeHooks.prepatch:updateChildComponent end
		componentVNodeHooks.prepatch->>-componentVNodeHooks.init:prepatch end
	else 
		componentVNodeHooks.init->>+createComponentInstanceForVnode:child=vnode.componentInstance=createComponentInstanceForVnode(vnode,parentVM)
		createComponentInstanceForVnode->>createComponentInstanceForVnode:new vnode.options.Ctor({_isComponent:true,_parentVnode:vnode,parentVM})
		createComponentInstanceForVnode->>-componentVNodeHooks.init:创建component实例
		componentVNodeHooks.init->>componentVNodeHooks.init:child.$mount():手动挂载
	end
	componentVNodeHooks.init->>-createComponent:componet创建完毕
	createComponent->>+initComponent:initCompon
	initComponent->>initComponent:vnode.elm = vnode.componentInstance.$el,childCmp会先与pCmp挂载
	initComponent->>initComponent:invoke cbs.create,vnode.data.hook.create,insertQueue.push(vnode)
	initComponent->>-createComponent:initComponent end
	createComponent->>createComponent:insert(parentElm,vnode.elm,sibling)
	createComponent->>-createElm:createElm
else
	createElm->>createElm:vnode.ele=nodeOps.createEle
	createElm->>createElm:setScop(vnode)
	createElm->>+createChildren:createChildren(vnode,children,insertQueue)
	createChildren->>createElm:循环创建所有的children
	createChildren->>-createElm:createChildren end
	createElm->>createElm:invoke cb.create
	createElm->>createElm:invoke vnode.data.hook.create(),insertQueue.push(vnode)
	createElm->>createElm:nodeOpts.appendChild(parent,elm) or nodeOpts.insertBefore(parent,elm,sibling)
end
createElm->>-__patch__:创建新的dom节点完毕
patchVNode->>-__patch__:更新现有的dom节点完毕
__patch__->>__patch__:vnode.data.hook.insert()
__patch__->>-_update:patch end
_update->>-_update:dom更新结束
sequenceDiagram
destroy->>+destroy:destroy
destroy->>destroy:call hook beforeDestroy
destroy->>destroy:vm.watcher.teardown
destroy->>+__patch__:vm.__patch__(vm._vnode, null)
__patch__->>+invokeDestroyHook:invokeDestroyHook
invokeDestroyHook->>invokeDestroyHook:invoke options.data.hooks.destory
invokeDestroyHook->>invokeDestroyHook:invoke cbs.destory
invokeDestroyHook->>invokeDestroyHook:invokeDestroyHook(children)
invokeDestroyHook->>-invokeDestroyHook:invokeDestroyHook end
__patch__->>-destroy:销毁节点end
destroy->>destroy:call hook destroyed
destroy->>destroy:vm.$off
destroy->>-destroy:destroy end