万字长文剖析React一路升级下的动机React18于2022年3月29日正式发布,正式开启了react并发

React16之前版本调度、渲染效率不高,新版本引入新机制进行全面优化。React框架内部的运作可以分为3层:

Reconciler层是调度任务的核心,旧版本的调度方式中,当我们调用setState更新页面的时候,React会用递归的方式遍历整颗组件数的所有节点,对比新旧虚拟DOM树,找出需要变动的节点,然后再更新UI。整个过程是一气呵成,不能被打断的。如果页面元素很多,整个过程占用的时机就可能超过16毫秒,就容易出现卡顿掉帧的现象。

React16中使用了Fiber,但是Vue是没有Fiber的,为什么呢?原因是二者的优化思路不一样:

Fiber可以理解为是一种数据结构,也可以理解为是一个执行单元。

Fiber可以理解为是一种数据结构,ReactFiber就是采用链表实现的,每个Fiber保存了节点处理的上下文信息,因为是手动实现的,所以更为可控,我们可以保存在内存中,随时中断和恢复。每个VirtualDOM都可以表示为一个fiber,如下图所示,每个节点都是一个fiber。一个fiber包括了child(第一个子节点)、sibling(兄弟节点)、return(父节点)等属性,ReactFiber机制的实现,就是依赖于以下的数据结构。

任务的拆分、执行、挂起、恢复以及高优先级任务插队是react更新任务的核心。

每一个dom元素就是一个Fiber,而一个Fiber可以理解为一个执行单元,所以一次更新任务被拆分成了以Fiber为单位的小任务。

requestIdleCallback调度fiber更新任务的伪代码如下:

例如,高优先级更新u1、低优先级更新u2的updatePriority分别为0、250,则

MAX_SIGNED_31_BIT_INT-(currentTime+0)>MAX_SIGNED_31_BIT_INT-(currentTime+200)//即u1.expirationTime>u2.expirationTime;代表u1优先级更高。

expirationTime算法的原理简单易懂:每次都选出所有更新中**「优先级最高的」**。

除此之外,还有个问题需要解决:如何表示批次?

批次是什么?考虑如下例子:

//定义状态numconst[num,updateNum]=useState(0);//...某些修改num的地方//修改的方式1updateNum(3);//修改的方式2updateNum(num=>num+1);两种修改状态的方式都会创建更新,区别在于:

由于第二种方式的存在,更新之间可能有连续性。所以expirationTime算法计算出一个优先级后,组件render时实际参与更新当前状态的值的是:

这些相互关联,有连续性的更新被称为一个批次(batch)。expirationTime算法计算批次的方式也简单粗暴:优先级大于某个值(priorityOfBatch)的更新都会划为同一批次。

constisUpdateIncludedInBatch=priorityOfUpdate>=priorityOfBatch;expirationTime算法保证了render异步可中断、且永远是最高优先级的更新先被处理。

ReactFiber与浏览器的核心交互流程如下

但是react并没有用requestIdleCallback来执行Fiber更新任务,主要原因有两点

出现空闲时段的场景:

requestAnimationFrame+MessageChannel实现requestIdleCallback代码如下

在React得到控制权后,应该优先处理高优先级的任务。也就是说正在处理的任务可能会被中断,在恢复时会让位给高优先级任务,原本中断的任务可能会被放弃或者重做。但是如果不按顺序执行任务,可能会导致前后的状态不一致。比如低优先级任务将a设置为0,而高优先级任务将a递增1,两个任务的执行顺序会影响最终的渲染结果。因此要让高优先级任务插队,首先要保证状态更新的时序。

解决办法是:所有更新任务按照顺序插入一个队列,状态必须按照插入顺序进行计算,但任务可以按优先级顺序执行,例如:

上面被跳过任务不会被移除,在执行完高优先级任务后它们还是会被执行的。因为不同的更新任务影响的节点树范围可能是不一样的,举个例子a、b可能会影响Foo组件树,而c会影响Bar组件树。所以为了保证视图的最终一致性,所有更新任务都要被执行。

道理讲起来都很简单,ReactFiber实际上非常复杂,不管执行的过程怎样拆分、以什么顺序执行,最重要的是保证状态的一致性和视图的一致性

从React16.3之后,React团队就对生命周期进行了调整,React16.3之前的生命周期如下:

React16.3之后的生命周期如下:

通过对比可以发现之前的生命周期钩子函数componentWillMount,componentWillReceiveProps,componentWillUpdate被废弃,新增了staticgetDerivedStateFromProps(newProps,prevState)和getSnapshotBeforeUpdate(prevProps,prevSteate),之所以废弃掉三个生命周期是因为原来(Reactv16.0前)的生命周期在Reactv16推出Fiber之后就不合适了,因为如果要开启asyncrendering,组件在更新过程中有可能会被暂停和恢复更新,所以执行时机在render函数之前的所有钩子函数,都有可能被执行多次。如果在这些钩子函数里做副作用操作,比如发起请求,事件监听等可能会导致内存泄漏,这三个生命周期方法在v17以前仍然保留,新增了带UNSAFE_前缀的3个方法,v16.x版本中,新旧的方法依旧都可以使用,但是使用不带UNSAFE_前缀的方法,将提示被弃用的警告。

新增了两个钩子函数具体使用如下:

当我们要学习一个新事物的时候,我们应该做的第一件事就是问自己两个问题:

我们最初在写类组件时一定遇到过如下的问题:

withAuth(withRouter(withUserStatus(UserDetail)))这种嵌套写法的高阶组件可能会导致很多问题,其中一个就是props丢失的问题,例如withAuth传递给UserDetail的某个prop可能在withUserStatus组件里面丢失或者被覆盖了,且容易发生wrapperhell(嵌套地狱)

hooks的出现就是用来解决以上类组件面临的问题,实际上就两句话:易维护,易复用。

talkischeap,我们先看两个代码片段:

在类组件中

再来看看函数组件中:

在第一个例子打印结果:12345

在第二个例子打印结果:00000

在讲解hooks原理前先提两个问题:

在组件初始化的时候,每一次hooks执行,如useState(),useRef(),都会调用mountWorkInProgressHook,这个函数会产生一个hook对象,并形成链表结构,绑定在当前组件对应的Fiber(也称为workInProgress)对象的memoizedState属性上,每个hook对象又有如下属性:

对于effect副作用钩子,会把当前需要执行的副作用以链表的形式绑定在当前组件对应的Fiber对象的updateQueue属性上,等组件更新完毕后依次执行副作用。

假设一个组件中调用了useState、useMemo、useRef、useEffect,那么最终形成的结构如下图:

如果我们将其中的一个useRef放入条件语句中,

首先会以当前current组件树为基础复制一份workInProgress树,并将current树上的hooks信息复制过来。各hooks工作如下:

至于其他的几个hook是类似的,例如useReducer和useState类似,useCallback和useMemo类似。

React17发布日志上说这次版本最大的特点就是无新特性,但是仔细研究后还是有很多东西值得学习的。

React16可中断更新可以解决以下问题:

这些问题统称为CPU密集型问题。

在前端,还有一类问题也会影响体验,那就是请求数据或懒加载造成的等待。这类问题被称为IO密集型问题。

为了解决IO密集型问题,React提出了Suspense。

React.Suspense可以指定加载指示器(loadingindicator),以防其组件树中的某些子组件尚未具备渲染条件。在未来,我们计划让Suspense处理更多的场景,如数据获取等。

考虑如下代码:

假设组件Sub三秒后被加载,理想情况下,在加载前后UI会依次显示为:

Suspense带来了多任务并发执行的直观感受。

那么Suspense对应更新的优先级是高还是低呢?

当加载成功后,合理的逻辑应该是尽快展示成功后的UI。所以Suspense对应更新应该是高优先级更新。那么,在示例中共有两类更新:

在expirationTime算法下:

//u0优先级远大于u1、u2、u3...u0.expirationTime>>u1.expirationTime>u2.expirationTime>…u0优先级最高,则u1及之后的更新都需要等待u0执行完毕后再进行。

而u0需要等待加载成功才能执行。所以,加载成功前后UI会依次显示为:

所以,只考虑CPU密集型场景的情况下,高优先级更新先执行的算法并无问题。

但考虑IO密集型场景的情况下,高优先级IO更新会阻塞低优先级CPU更新,这显然是不对的。

所以expirationTime算法并不能很好支持并发更新。

expirationTime算法最大的问题在于:expirationTime字段耦合了优先级与批次这两个概念,限制了模型的表达能力。

这导致高优IO更新不会与低优CPU更新划为同一批次。那么低优CPU更新就必须等待高优IO更新处理完后再处理。

如果不同更新能根据实际情况灵活划分批次,就不会产生这个bug。

新的调度算法被称为Lane(车道),他是如何定义优先级与批次呢?

对于优先级,一个lane就是一个32bitInterger,最高位为符号位,所以最多可以有31个位参与运算。

不同优先级对应不同lane,越低的位代表越高的优先级,比如:

//对应SyncLane,为最高优先级0b0000000000000000000000000000001//对应InputContinuousLane0b0000000000000000000000000000100//对应DefaultLane0b0000000000000000000000000010000//对应IdleLane0b0100000000000000000000000000000//对应OffscreenLane,为最低优先级0b1000000000000000000000000000000批次则由lanes定义,一个lanes同样也是一个32bitInterger,代表一到多个lane的集合,该整数所有二进制位为1对应的优先级任务都将被执行。例如lanes为17(10001)时,表示将并行更新SyncLane(值为1)和DefaultLane(值为16)的任务,这两个任务属于同一批次。

可以用位运算很轻松的将多个lane划入同一个批次:

//要使用的批次letlanesForBatch=0;constlaneA=0b0000000000000000000000001000000;constlaneB=0b0000000000000000000000000000001;//将laneA纳入批次中lanesForBatch|=laneA;//将laneB纳入批次中lanesForBatch|=laneB;//lanesForBatch=0b0000000000000000000000001000001//新的优先级为0b0000000000000000000000001000001//更新时会将各个位上的1对应的任务一同更新,也就是一个批次上文提到的Suspense的bug是由于expirationTime算法不能灵活划定批次导致的。

lanes就完全没有这种顾虑,任何想划定为同一批次的优先级(lane)都能用位运算轻松搞定。

React17以前,React中如果使用JSX,则必须像下面这样导入React,否则会报错,这是因为旧的JSX转换会把JSX转换为React.createElement(...)调用。

而React17带来了改变,可以让我们单独使用JSX而无需引入React。这是因为新的JSX转换不会将JSX转换为React.createElement,而是自动从React的package中引入新的入口函数并调用,开发者可以不依赖于React的导入。

另外此次升级不会改变JSX语法,旧的JSX转换也将继续工作。

在React16或更早版本中,React会由于事件委托对大多数事件执行document.addEventListener()。但是一旦你想要局部使用React,那么React中的事件会影响全局。尤其在微前端中,不同的子工程可能会相互影响。

React17不再将事件添加在document上,而是添加到渲染React树的根DOM容器中。

下图形象描述了这次的变更,图片来自React官网

在React17以前,如果想要用异步的方式使用事件e,则必须先调用e.persist()才可以,这是因为React在事件池中重用了不同事件的事件源对象,以提高性能,并将所有事件字段在它们之前设置为null。

React17之前的调用方式:

handerClick=(e)=>{console.log(e.target)//button//必需要加e.persist()e.persist()setTimeout(()=>{console.log(e.target)//button},0)}React17之后的调用方式:

handerClick=(e)=>{console.log(e.target)//buttonsetTimeout(()=>{console.log(e.target)//button},0)}React17实验版(并发更新的尝试)React17实验版本是一个过渡版本,为React18正式启用并发更新做铺垫,来看看React17做了哪些工作?它与正式发布的React18有什么不同?

可以从架构角度来概括下,当前一共有两种架构:

新架构可以选择是否开启并发更新,所以当前市面上所有React版本一定属于如下一种情况:

React团队的愿景是:

使用老版本的开发者可以逐步升级到新版,即从情况1、2、3向情况4升级。

但是这中间存在极大的阻力,因为情况4的React一些行为异于情况1、2、3。

比如如下三个生命周期函数在情况4的React下是“不安全的”:

贸然升级可能造成老代码不兼容。

渐进升级方案的第一步是规范代码。

v16.3新增了StrictMode,对开发者编写的不符合并发更新规范的代码作出提示,逐步引导开发者写出规范代码。

比如,使用上述不安全的生命周期函数时会产生如下报错信息:

下一步,React团队让不同情况的React可以在同一个页面共存,借此可以让情况4的React逐步渗入原有的项目。

具体做法是提供三种开发模式:

官网的一张图片很直观的说明了三种模式

在与社区进行大量沟通后,React团队意识到当前的渐进升级策略存在两方面问题。

首先,由于模式影响的是整个应用,所以无法在同一个应用中完成渐进升级。

举个例子,开发者将应用中ReactDOM.render改为ReactDOM.createBlockingRoot,从Legacy模式切换到Blocking模式,这会自动开启StrictMode。

此时,整个应用的并发不兼容警告都会上报,开发者还是需要修改整个应用。

从这个角度看,并没有起到渐进升级的目的。

其次,React团队发现:开发者从新架构中获益,更多是由于使用了并发特性(ConcurrentFeature)。

并发特性指开启并发更新后才能使用的特性,比如:

所以,可以默认情况下仍使用同步更新,在使用了并发特性后再开启并发更新。

在v18中运行如下代码:

如果updateCount没有作为startTransition的回调函数执行,那么updateCount将触发默认的同步更新。

所以,在v18中,不再有三种模式,而是以是否使用并发特性作为是否开启并发更新的依据。

具体来说,在v18中统一使用ReactDOM.createRoot创建应用。

当不使用并发特性时,表现如情况3。使用并发特性后,表现如情况4。

在上节React17实验版中我们已经得到了结论:在v18中统一使用ReactDOM.createRoot创建应用,当不使用并发特性时,更新仍然是同步更新(不可中断更新),且默认是批量更新,当使用并发特性后,为并发更新,下面聊聊React18的一些新特性。

批处理是react将多个状态更新分组到一个渲染中以获得更好的性能。react18之前只能在react事件处理程序中批处理更新。默认情况下,Promise、setTimeout、本机事件处理程序或任何其他事件内部的更新不会在React中批处理。

React18自动使用自动批处理,这些更新将自动批处理:

//示例一:react17会render两次,react18只需要render一次consthandleClick=()=>{Promise.resolve().then(()=>{setC1((c)=>c+1);});setC2((c)=>c+1);};那么,如果我不想要批处理呢?

官方提供了一个APIflushSync用于退出批处理

//会更新两次functionhandleClick(){flushSync(()=>{setC1((c)=>c+1);});setC2((c)=>c+1);}flushSync会以函数为作用域,函数内部的多个setState仍然为批量更新,这样可以精准控制哪些不需要的批量。

componentDidUpdate(){console.log('didmount');}handleClick=()=>{setTimeout(()=>{console.log('开始运行setTimeout')flushSync(()=>{this.setState({},()=>{console.log('更新1')})this.setState({},()=>{console.log('更新2')})});this.setState({},()=>{console.log('更新3')})this.setState({},()=>{console.log('更新4')})console.log('结束运行setTimeout')});console.log('结束运行')}//flushSync将四个setState()分为了两组:更新1和更新2为一组、更新3和更新4为一组//打印顺序如下://开始运行setTimeout//didmount//更新1//更新2//结束运行setTimeout//didmount//更新3//更新4实现原理自动批处理的实现在React18中是基于优先级的,用lane模型来进行优先级的控制。lane用来弥补expirationTime的缺陷,它首先说明这个任务是个什么任务(确定优先级,确定lane值),其次说明哪些任务应该被batching到一起做(lane相同即batching到一起做)。然后通过lanes确定哪些并行更新。关于lane模型可以参见React17正式版这一小节中的Lane优先级算法。

批处理实现的核心在于当相同优先级的更新发生时,并不会生成新的任务,而是复用上一次的任务,从而实现合并。

flushSync实现原理更简单,它将内部更新的优先级强制指定为SyncLane,即指定为同步优先级,具体效果就是每一次更新时都会同步的执行渲染。

过渡是React18中的一个新概念,用于区分紧急和非紧急更新。紧急更新反映了直接交互,例如键入、单击、按下等。非紧急(过渡)更新将UI从一个视图转换到另一个视图。

打字、点击或按下等紧急更新需要立即响应,以符合我们对物理对象行为方式的直觉。否则用户会觉得“不对劲”。但是,过渡是不同的,因为用户不希望在屏幕上看到每个中间值。

下面我们来看一个例子:当滑块滑动时,下方的图表会一起更新,然而图表更新是一个CPU密集型操作,比较耗时。由于阻塞了渲染导致页面失去响应,用户能够非常明显的感受到卡顿。

实际上,当我们拖动滑块的时候,需要做两次更新:

//紧急更新setSliderValue(input);//非紧急更新setGraphValue(input);startTransition包装在startTransition中的更新被视为非紧急更新,也就是它的优先级被降低,如果出现更紧急的更新(如点击或按键),则会中断。默认的更新被视为紧急更新,也就是没有开启并发特性时的更新为同步更新,是不可中断的,表现和React18之前一样。

import{startTransition}from'react';//紧急更新setSliderValue(input);//非紧急更新startTransition(()=>{//Transition:ShowtheresultssetGraphValue(input);});使用后效果:

上述的问题能够把setGraphValue的更新包装在setTimeout内部,像如下这样:

通过setTimeout确实可以让输入状态好一些,但是由于setTimeout本身也是一个宏任务,而每一次input触发onchange事件也是宏任务,所以setTimeout还是会影响页面的交互体验。相当于是将setGraphValue(input)更新任务对页面的阻塞推迟到了下一个事件循环。

通过对比,startTransition相比于setTimeout的优势在于:

那么我们再想一个问题,为什么不是节流和防抖。首先节流和防抖能够解决卡顿的问题吗?答案是一定的,在没有transition这样的api之前,就只能通过防抖和节流来处理这件事。接下来用防抖处理一下。

上面介绍了startTransition,又讲到了过渡任务,本质上过渡任务有一个过渡期,在这个期间当前任务本质上是被中断的,那么在过渡期间,应该如何处理呢,或者说告诉用户什么时候过渡任务处于pending状态,什么时候pending状态完毕。

为了解决这个问题,React提供了一个带有isPending状态的hooks——useTransition。useTransition执行返回一个数组。数组有两个状态值:

import{useTransition}from'react'/*使用*/const[isPending,startTransition]=useTransition()那么当任务处于悬停状态的时候,isPending为true,可以作为用户等待的UI呈现。比如:

useDeferredValue和上述useTransition本质上有什么异同呢?

相同点:

不同点:

举个例子来更好的理解useDeferredValue

SSR有点像“魔术”。它不能使你的应用程序更快地完全可交互。相反,它让你更快地展示你的应用程序的非交互式版本。

SSR的整个过程是一个串行的,总结一下就是:获取数据(服务器)→渲染成HTML(服务器)→加载代码(客户端)→hydration(客户端)。任何一个阶段都不能在前一个阶段结束之前开始。

在目前的API中,当你渲染到HTML时,你必须已经在服务器上为你的组件准备好所有的数据。这意味着你必须在服务器上收集所有的数据,然后才能开始向客户端发送任何HTML。这样是很低效的。

在JavaScript代码加载后,React将HTML“hydrate”并使其具有交互性。客户端在渲染组件时将“走”过服务器生成的HTML,并将事件处理程序绑定到该HTML上。为了使其发挥作用,组件在浏览器中生成的树必须与服务器生成的树相匹配。否则React就不能“匹配它们!”这样做的一个非常不幸的后果是,必须在客户端加载所有组件的JavaScript,才能开始对任何组件进行hydration

React一次性完成树的hydration。这意味着,一旦它开始hydrate,React就不会停止hydration的过程,直到它为整个树完成hydration。因此,必须等待所有的组件被hydrated,才能与任何组件进行交互。

SSR存在的问题的根源是因为整个过程是一个“瀑布”(流程):获取数据(服务器)→渲染成HTML(服务器)→加载代码(客户端)→hydration(客户端)。任何一个阶段都不能在前一个阶段结束之前开始。这就是为什么它的效率很低。

React18的解决方案是将工作分开,这样就可以为屏幕的一部分而不是整个应用程序做这些阶段的工作。

React18中,有两个主要的SSR功能是由Suspense解锁的。

流式HTML

选择性hydration

所有组件完成hydration之前与页面互动

React18为SSR提供了两个主要功能:

这些功能解决了React中SSR的三个长期存在的问题:

useId是一个新的hook,用于在客户端和服务器上生成唯一ID,同时避免hydrationmismatches。

当我们在使用React进行服务端渲染(SSR)时就会遇到一个问题:如果当前组件已经在服务端渲染过了,但是在客户端我们并没有什么手段知道这个事情,于是客户端还会重新再渲染一次(双端对比),这样就造成了冗余的渲染。

因此,react18提出了useId这个hook来解决这个问题,它使用组件的树状结构(在客户端和服务端都绝对稳定)来生成id。

THE END
1.全身经络疏通接待流程与操作流程操作流程: 有一个k核心,话在手前。 要做什么 先要告知客人。之后再着手做。 a、客人平躺在床上。技师站于客人右侧, 告知客人 项目服务的时长及大概流程。 今天咱们做的全身经络疏通,预计20分钟左右。 做身体的正面背面 从头到脚的穴位按摩 全身的拍打放松。 https://www.jianshu.com/p/b5462acc0c1b
2.18道流程做的很仔细的男士spa店18道流程做的很仔细的男士spa店 各位男同胞们,我要把私藏了很久的这家专业男士SPA店分享出来! 这是今年以来我去过的觉得最赞的SPA店了!集服务+环境+技师+手法与一体的精品店,错过就要后悔莫及了!店里的环境那叫一个气派优雅,等待区很舒适,有很多不同的饮料可以选,随心喝都免费~~ 里面房间超多的,都是...https://m.dianping.com/ugcdetail/226718514?sceneType=0&bizType=29&msource=baiduappugc
3.www.kzjiancai.cn/mmmj31139287.shtml对标管理特别强调持续改进的观念、有循环再生特性的流程。它不是一个短期的活动,也不是一次就完成的活动。通过对对标企业的不断对照和学习,了解人力资源领域最先进的作业技术及管理方式,激发企业人力资源的创意,推动企业的持续改进和不断创新。 (4)打造特色。融合历史文化、国情和实践,探索中国企业人力资源管理的特色...http://www.kzjiancai.cn/mmmj31139287.shtml
4.用于治疗法布里病的方法和组合物与流程21.在一些实施方案中,所述表达构建体以约5.0e+12至1.0e+14个载体基因组/千克(vg/kg)的剂量施用于受试者。 22.在一些实施方案中,将所述表达构建体施用于受试者的肝脏。在其它实施方案中,所述表达载体通过静脉内输注施用于受试者。在还有其它实施方案中,仅将一剂表达构建体施用于所述受试者。 http://xjishu.com/zhuanli/05/202080010090.html
1.体验给起飞降落spa术语起飞降落SPA术语解密:航空知识问答 --- 起飞篇 问题1:什么是V1速度? 回答:V1速度是指在起飞过程中,如果达到该速度后发生引擎故障,飞行员会继续起飞而不中断,保证飞机的安全性能。 问题2:起飞速度中的VR是什么意思? 回答:VR是指旋转速度,即飞机在起飞过程中,飞行员将飞机的机头抬起,使飞机离开地面。 问题3:...https://www.yeeper-dairy.com/news/news_detail/1411n.jpgl?wap=View&aid=802088
2.完整的HOMESPA流程来咯~FORVIL品牌主理人@大忙人施老师从听觉、嗅觉、触觉等五感六觉的角度手把手为大家讲解头部HOME SPA洗前、洗中、洗后的养护流程宅家也能享受一次身心的疗愈快收藏起来,给自己安排一场 #头部按摩 #按摩头皮 #给头部做个护理 #改善头痛偏头痛失眠 #头部护理 #按摩头部仪器 #养发好物 #梳头的好处和功效与作用...https://m.dewu.com/note/trend/details?id=246085997
3.堪称2024最强的前端面试嘲题,让419人成功拿到offer32. 为什么 SPA 应?都会提供?个 hash 路由,好处是什么? 33.[React] 如何进?路由变化监听 34. 单点登录是是什么, 具体流程是什么 35. web 如何禁?别?移除?印 36. 访问?屏了, 原因是啥, 如何排查? https://maimai.cn/article/detail?fid=1835361421&efid=oa5JXyziIhwZpL8_jbOwrw
4.www.nccode.cn/apfccd58852505.shtmlRoblox过去四个季度的现金收入增长超过22%,达到9.552亿美元,同期产生了5.76亿美元的自由现金流。公司发言人强调,这些数据是Roblox一贯向投资者强调的指标,并坚信Roblox是一个安全的平台。 《TheBearCave》是一个专门给那些喜欢做空股票的人看的财经新闻通讯。该网站的运营者EdwinDorsey在2022年的时候发表了一份该平台的...http://www.nccode.cn/apfccd58852505.shtml
5.arab.hbqx.cn/fancai73952922有一个男的把鸡鸡插进美女屁股里的视频软件下载 伊人影院在线观看 免费在黄色视频在哪里 「王者荣耀伽罗太华被×哭还流东西漫画」衍生小说免费阅读_中青网 婷婷五月开心亚洲综合在线 av久草 寡妇门全特级毛片大抽插 美女高潮呻吟久久久极品APP xxx69视频 pr九天狐正能量视频在线观看高清 午夜综合社 cao18 ...http://arab.hbqx.cn/fancai73952922
6.vue面试题51CTO博客18、axios同时请求多个接口,如果当token过期时,怎么取消后面的请求? 答:javascript:void(0)19、从0到1自己构架一个vue项目,说说有哪些步骤、哪些重要插件、目录结构你会怎么组织 答:https://github.com/haizlin/fe-interview/issues/98320、你知道vue的模板语法用的是哪个web模板引擎...https://blog.51cto.com/u_15726982/5690015
7.手边酒店小程序yyfhotel25.0(1).18.rar酒店小程序资源js:50个 需积分: 5148 浏览量2023-06-09上传2.05MBRAR 【手边酒店小程序 yyf_hotel 25.0(1).18.rar】是一个针对酒店行业的微信小程序应用,主要用于提供便捷的酒店预订、管理和服务功能。这个版本号为25.0.18的更新包,包含了安装和升级的所有必要文件,确保用户能够顺利地在现有版本基础上进行升级或全新安装。 https://download.csdn.net/download/2301_78600126/87884082
8.pseinu.cn/xxxr/768887.shtml2023年5月,克劳斯公告披露,KM集团2022年度和2023年第一季度持续亏损。为进一步降低运营成本,KM集团拟实施以组织结构优化、组织流程优化、工作岗位精简、降本提质增效为核心的调整计划和效率计划项目。在此次调整中,KM集团拟在全球范围内精简不超过790个工作岗位,在德国精简不超过490个工作岗位。 https://pseinu.cn/xxxr/768887.shtml
9.www.huojuyude.com/yyys40650094上海少妇丁字裤SPA按摩 伦理片免费 日韩经典久久久 嫩白臀 春药痉挛HDvideosex 久久久婷婷精品人妻8888 前面两个小兔兔被?的上下抖 欧美赛三A大片免费看 日本操逼网站 男人把鸡巴插进女人的那个朱竹清 大陆偷拍 兰氏牝户 你把我片儿操逼视频 91久久工口网站 中国小臊逼丁香按摩推油按...http://www.huojuyude.com/yyys40650094
10.美容院活动方案(精选20篇)一、邀宴客人:请老顾客带2个以上朋友参加,国庆节发廊活动方案。 二、会议流程:(18:30——21:00) 1、主持人公布晚会开始。 2、美容师表演《感恩的心》。 3、老板代表致感谢词。 4、颁奖。 A、感谢20xx年对xx美容院给予的最大支持、消费最高的忠实朋友xxx特奖大礼一份。 https://www.unjs.com/huodongfangan/202211/5866702.html
11.美容院活动方案(通用20篇)一、邀请客人:请老顾客带2个以上朋友参加。(4.15-4.19) 二、会议流程:(18:30——21:00) (1)主持人宣布晚会开始 (2)美容师表演《感恩的心》 (3)老板代表致感谢词 (4)颁奖A感谢20xx年对xxx美容院给予的支持、消费的'忠实朋友xxxxxxxxx特奖大礼一份xxxxxxxx,凡是xx美容院新老顾客均有一份精美礼品xxxxxxxxx(...https://www.oh100.com/kaidian/3968050.html