【编程的源码代码】【双语 企业 php 源码】【在线娃娃机 源码】忙循环源码_循环源代码

时间:2024-11-15 06:04:35 来源:cosamp.cpp源码 分类:综合

1.UE4动画系统播放Montage源码浅析(二)
2.Vue2剥丝抽茧-响应式系统之nextTick
3.解读useEffect和useLayouEffect原理

忙循环源码_循环源代码

UE4动画系统播放Montage源码浅析(二)

       在先前的忙循码循文章中,我们对UE4动画蒙太奇播放过程进行了探讨,环源环源本篇将深入解析蒙太奇的代码其他相关知识,包括蒙太奇插槽、忙循码循蒙太奇片段和动画片段等。环源环源所分析的代码编程的源码代码源码版本为4.。

       关于蒙太奇结构,忙循码循UAnimMontage蒙太奇动画可视为一种动态表现手段,环源环源无需将混合空间或动画序列拖入动画蓝图,代码只需在动画蓝图里放置一个FAnimNode_Slot动画节点,忙循码循即可通过montage_play接口播放该插槽下的环源环源所有蒙太奇资源。

       这意味着我们无需修改动画蓝图,代码双语 企业 php 源码就可以播放全新的忙循码循动作。

       蒙太奇动画除了动态播放动作外,环源环源还有更多应用。代码例如,现实中的蒙太奇概念。蒙太奇(montage)在法语中意为“剪接”,但在俄国,它被发展成一种**中镜头组合的理论。例如,将母亲煮菜、洗衣、在线娃娃机 源码带小孩、父亲看报等镜头放在一起,会给人一种母亲“忙碌”的感觉,从而产生对比手法,突出人物或事物的具体特征,两个不同的片段之间相互联系,产生意想不到的效果。

       如上所述,这类动画被称为蒙太奇,因为它还包括剪接、片段、红名自动开枪源码组合等特点,可用于循环播放动画、跳转到下一个动画等。

       创建一个动画序列的蒙太奇,会看到如下面板:区域1为蒙太奇插槽,在动画蓝图中也要有对应插槽节点才会播放此蒙太奇;蒙太奇资源中可以添加多个插槽。区域2为蒙太奇片段,蒙太奇资源中可以创建多个片段并设置它们之间的关系,用于动画的跳转、循环等。区域3为动画片段,表单静态页面源码每个插槽下可以添加多个动画片段。

       蒙太奇片段对应上图示例有三个片段:Default、Loop、End,我们可以设置它们之间的关系。图中Default片段后面的箭头图标表示播放完毕后会接着播放Loop,Loop片段后的循环图标表示循环播放Loop。如果我们显式跳转到End片段,End片段后面没有其他片段,那么播放结束后就结束了。

       蒙太奇片段是独立的,与插槽、动画片段没有任何关系,它只是根据蒙太奇片段之间的关系确定当前播放时间。了解了蒙太奇片段的作用,我们来看具体实现。其数据结构如下:蒙太奇片段由FCompositeSection结构描述,CompositeSections就是蒙太奇资源上序列化的蒙太奇片段数组。

       了解了基本数据结构,再看如何根据动画片段获取蒙太奇姿势。结合上一篇文章,姿势获取最后是调用FAnimInstanceProxy::SlotEvaluatePose函数,并遍历MontageEvaluationData数据(其中包含蒙太奇实例的时间、权重、蒙太奇引用等数据)。

       以上便是关于UE4动画系统播放Montage源码的解析,希望对大家有所帮助。

Vue2剥丝抽茧-响应式系统之nextTick

       在 Vue2 的源码解析系列文章中,探讨响应式系统的核心概念——nextTick。了解 dom 更新机制,认识到浏览器中的 js 引擎线程与 GUI 渲染线程交替执行,且 dom 更新发生在 js 线程,但需要渲染线程绘制后,用户才能观察到。因此,若 js 线程执行过长,可能无法及时将更新的 dom 显示给用户。

       以极端情况为例,即使在js 线程中修改了 dom,如果 js 线程忙于执行其他任务,导致渲染线程未能及时绘制更新的 dom,用户将无法看到这些修改。引入 bundle.js 的情况下,即便修改了 dom,如果 js 线程陷入死循环,用户界面仍会保持空白状态,尽管 dom 已经更新。

       值得注意的是,在 js 线程中连续修改同一 dom 元素,最终渲染时,显示的 dom 结果是最后一次修改后的状态。即使在 js 线程中进行了多次修改,最终呈现给用户的 dom 结果只会是最后一次修改的结果。

       讨论到 js 线程中的宏任务与微任务队列,简单阐述宏任务与微任务的概念,以及它们如何影响事件循环的执行顺序。然而,这里不深入探讨具体实现细节,读者可进一步研究相关资料以获取更多深入理解。

解读useEffect和useLayouEffect原理

       èƒŒæ™¯

       å†™è¿™ç¯‡æ–‡ç« æ˜¯å› ä¸ºå·¥ä½œä¸Šä¸æ˜¯éžå¸¸ç¹å¿™ï¼Œå¯ä»¥æŠ½ç©ºå­¦ä¹ è‡ªå·±å¸¸ç”¨æ¡†æž¶å’Œç±»åº“,深入理解它们,在技术上希望有更大的进步,培养学习兴趣;

useEffect

       å’Œå…¶å®ƒhooks一样,加载和更新执行不一样的方法(mountEffect和updateEffect);

1.mountEffect

       é¡µé¢åŠ è½½æ—¶ï¼Œæ‰§è¡ŒmountEffect;

       åˆ›å»ºhook对象,加入组件的hook单向链表;

       åœ¨ç»„件的fiber的flag中加入副作用相关的effectTag;(加载期间默认有layoutEffect和effect的副作用)

       åˆ›å»ºeffect对象,给hook对象的memoizedState和加入组件fiber的updateQueue中形成effect环状链表;在渲染工作完成后,会循环这个环状链表,执行每个effect对象的destory和create;

consteffect={ tag,create,destroy,deps,next:null};tag是effect的类型tag为9是useEffect,5是useLayoutEffectcreate是useEffect或useLayoutEffect的回调函数destroy是create返回的回调函数deps是useEffect或useLayoutEffect的依赖数组next指向下个effect对象;1.1.effect环状链表图functionpushEffect(tag,create,destroy,deps){ consteffect={ tag,create,destroy,deps,next:null};//新创建的effect对象为最后为effect链表的一个effect对象,componentUpdateQueue.lastEffect会指向新创建的effect对象//新创建的effect对象的next会指向第一个effct对象;letcomponentUpdateQueue=(currentlyRenderingFiber.updateQueue);if(componentUpdateQueue===null){ //当前没有updateQueuecomponentUpdateQueue=createFunctionComponentUpdateQueue();//创建updateQueuecurrentlyRenderingFiber.updateQueue=componentUpdateQueue;//形成一个环状链表componentUpdateQueue.lastEffect=effect.next=effect}else{ constlastEffect=componentUpdateQueue.lastEffect;if(lastEffect===null){ componentUpdateQueue.lastEffect=effect.next=effect;}else{ //第一个effect对象为最先创建的的effect对象constfirstEffect=lastEffect.next;//获取第一个effect对象lastEffect.next=effect;//旧的最后一个effect对象的next,指向新创建的effecteffect.next=firstEffect;//新创建的effect对象的next指向第一个effectcomponentUpdateQueue.lastEffect=effect;//updateQueue的lastEffect指向effect,新创建的effect变为最后一个effect对象}}returneffect;}2.updateEffect

       é¡µé¢æ›´æ–°æ—¶ï¼Œæ‰§è¡ŒupdateEffect;

       æ ¹æ®hook单向链表获取对应的更新时的hook对象,创建新的hook对象,加入hook单向链表;

       å¦‚æžœeffect的deps不为null,或者undefined,会从当前hook对象拿到上一次effect对象,再从effect对象拿到deps和destroy,用新的deps与之比较;

       å¦‚果新老deps相等,push一个不带HookHasEffect的tag给effect对象,加入updateQueue环状链表(这个effect不会被标记为有副作用,所以,effect的create和destroy不会被执行),不更新hook.memoizedState;

       å¦‚果新老deps不相等,更新effect对象,在effect的tag中加入HookHasEffect和上一次create执行的destroy,更新hook.memoizedState;

3.useEffct的回调函数和销毁函数的执行时机

       åœ¨render时期构建effect链表;在commit时执行先执行之前没有执行完的useEffect,然后,在beforeMutation阶段操作dom前,以NormalPriority常规优先级添加一个异步任务到任务队列(这个异步任务是用来执行useEffect的destroy和create的),在layout阶段完成,页面完成渲染后,执行在beforeMutation阶段添加的异步任务;

3.1.commit开始时

       ä¸»è¦æ˜¯ä¸ºäº†æ‰§è¡Œä¹‹å‰æ²¡æœ‰æ‰§è¡Œçš„useEffect

       è¿›å…¥commit阶段,这和useEffect异步调度的特点有关,它以一般的优先级被调度,意味着一旦有更高优先级的任务进入到commit阶段,上一次任务的useEffect还没得到执行。所以在本次更新开始前,需要先将之前的useEffect都执行掉,以保证本次调度的useEffect都是本次更新产生的。

functioncommitRootImpl(root,recoverableErrors,renderPriorityLevel){ do{ //`flushPassiveEffects`willcall`flushSyncUpdateQueue`attheend,which//means`flushPassiveEffects`willsometimesresultinadditional//passiveeffects.Soweneedtokeepflushinginaloopuntilthereare//nomorependingeffects.//TODO:Mightbebetterif`flushPassiveEffects`didnotautomatically//flushsynchronousworkattheend,toavoidfactoringhazardslikethis.flushPassiveEffects();}while(rootWithPendingPassiveEffects!==null);...省略代码}3.2.beforeMutation

       åªä¼šå‘起一次useEffect调度,是异步调度,以NormalPriority常规优先级添加一个异步任务在任务队列中(push(timerQueue,newTask)),在页面渲染完成时,会执行这个异步任务

functioncommitRootImpl(root,recoverableErrors,renderPriorityLevel){ ...省略代码if((finishedWork.subtreeFlags&PassiveMask)!==NoFlags||(finishedWork.flags&PassiveMask)!==NoFlags){ if(!rootDoesHavePassiveEffects){ rootDoesHavePassiveEffects=true;scheduleCallback$1(NormalPriority,function(){ //添加一个异步任务到任务队列flushPassiveEffects();//Thisrendertriggeredpassiveeffects:releasetherootcachepool//*after*passiveeffectsfiretoavoidfreeingacachepoolthatmay//bereferencedbyanodeinthetree(HostRoot,Cacheboundaryetc)returnnull;});}}...省略代码}3.3.layout

       åŠ è½½æ—¶ï¼Œåªæ‰§è¡ŒuseEffect的create函数即可;

       å¦‚æžœpendingPassiveEffectsLanes是同步赛道,就在页面渲染完直接执行useEffect的create和destroy,在beforeMutation时添加的异步任务,不会执行useEffect的create和destory

if(includesSomeLane(pendingPassiveEffectsLanes,SyncLane)&&root.tag!==LegacyRoot){ //加载期间默认是不走这里的//这里也是执行useEffect的create,如果pendingPassiveEffectsLanes是同步赛道,//就在渲染完成后直接执行useEffect的create和destory//在beforeMutation时添加的异步任务执行时,不会执行useEffect的create和destoryflushPassiveEffects();}

       æ‰§è¡Œä¸Šä¸€æ¬¡useEffect的create返回的destroy,拿到函数组件fiber的updateQueue,循环这个effect环状链表,拿到effect对象的destroy执行;

functioncommitHookEffectListUnmount(flags,finishedWork,nearestMountedAncestor){ varupdateQueue=finishedWork.updateQueue;varlastEffect=updateQueue!==null?updateQueue.lastEffect:null;if(lastEffect!==null){ varfirstEffect=lastEffect.next;vareffect=firstEffect;do{ if((effect.tag&flags)===flags){ //Unmountvardestroy=effect.destroy;effect.destroy=undefined;if(destroy!==undefined){ { if((flags&Passive$1)!==NoFlags$1){ markComponentPassiveEffectUnmountStarted(finishedWork);}elseif((flags&Layout)!==NoFlags$1){ markComponentLayoutEffectUnmountStarted(finishedWork);}}safelyCallDestroy(finishedWork,nearestMountedAncestor,destroy);//执行destroy{ if((flags&Passive$1)!==NoFlags$1){ markComponentPassiveEffectUnmountStopped();}elseif((flags&Layout)!==NoFlags$1){ markComponentLayoutEffectUnmountStopped();}}}}effect=effect.next;}while(effect!==firstEffect);}}

       æ‰§è¡Œå®Œæ‰€æœ‰ç»„件的destroy,再执行create;同理,也是拿到函数组件fiber的updateQueue,循环这个effect环状链表,拿到effect对象的create执行,然后把create返回的destroy给effect对象(留着下着更新执行useEffect时用);

functioncommitHookEffectListMount(flags,finishedWork){ varupdateQueue=finishedWork.updateQueue;varlastEffect=updateQueue!==null?updateQueue.lastEffect:null;if(lastEffect!==null){ varfirstEffect=lastEffect.next;vareffect=firstEffect;do{ if((effect.tag&flags)===flags){ { if((flags&Passive$1)!==NoFlags$1){ markComponentPassiveEffectMountStarted(finishedWork);}elseif((flags&Layout)!==NoFlags$1){ markComponentLayoutEffectMountStarted(finishedWork);}}//Mountvarcreate=effect.create;effect.destroy=create();{ if((flags&Passive$1)!==NoFlags$1){ markComponentPassiveEffectMountStopped();}elseif((flags&Layout)!==NoFlags$1){ markComponentLayoutEffectMountStopped();}}{ vardestroy=effect.destroy;if(destroy!==undefined&&typeofdestroy!=='function'){ varhookName=void0;if((effect.tag&Layout)!==NoFlags){ hookName='useLayoutEffect';}elseif((effect.tag&Insertion)!==NoFlags){ hookName='useInsertionEffect';}else{ hookName='useEffect';}varaddendum=void0;if(destroy===null){ addendum='Youreturnednull.Ifyoureffectdoesnotrequireclean'+'up,returnundefined(ornothing).';}elseif(typeofdestroy.then==='function'){ addendum='\n\nItlookslikeyouwrote'+hookName+'(async()=>...)orreturnedaPromise.'+'Instead,writetheasyncfunctioninsideyoureffect'+'andcallitimmediately:\n\n'+hookName+'(()=>{ \n'+'asyncfunctionfetchData(){ \n'+'//Youcanawaithere\n'+'constresponse=awaitMyAPI.getData(someId);\n'+'//...\n'+'}\n'+'fetchData();\n'+"},[someId]);//Or[]ifeffectdoesn'tneedpropsorstate\n\n"+'LearnmoreaboutdatafetchingwithHooks:/post/