大厂进阶四:React源码解析之Fiber架构

news2024/9/20 6:38:55

本文主要内容:

1、React Concurrent
2、React15架构
3、React16架构
4、Fiber架构
5、任务调度循环和fiber构造循环区别

一、React Concurrent

React在解决CPU卡顿是会用到React Concurrent的概念,它是React中的一个重要特性和模块,主要的特点和原理如下

一、主要特点和优势
1、时间切片(Time Slicing)
允许将长时间运行的任务分割成小块,在不阻塞主线程的情况下逐步执行。例如,在一个复杂的数据计算或渲染大型组件树时,React可以将这些任务分成多个小片段,在每一帧的空闲时间里执行一部分,这样就不会导致页面出现卡顿,保证了页面的响应性。

对于用户体验来说至关重要,用户在操作过程中不会感觉到界面被冻结,仍然可以进行其他交互,比如滚动页面、点击按钮等。

2、 并发渲染(Concurrent Rendering)
React可以同时处理多个渲染任务,根据任务的优先级和紧急程度来合理安排渲染顺序。

对于有紧急更新(如用户交互导致的状态变化)和非紧急更新(如后台数据的缓慢加载更新)的场景非常有用。紧急更新会被优先处理,以确保用户操作能够立即得到反馈,非紧急更新则在合适的时机进行,避免影响性能。

3、Suspense 组件和懒加载(Lazy Loading)
Suspense组件用于在等待异步数据加载时显示一个加载状态或者回退内容。比如,当一个页面依赖于从服务器获取的数据来渲染组件时,在数据加载过程中可以显示一个加载动画,提升用户体验。

懒加载允许在真正需要的时候才加载组件或模块。例如,对于一个大型应用,某些页面或功能模块可能不是在初始加载时就需要的,通过懒加载可以减少初始加载时间,提高应用的启动速度。当用户导航到相应的页面或触发特定功能时,对应的组件或模块才会被加载。

二、工作原理

1、 任务调度
React内部有一个任务调度器,它负责管理和分配任务的执行时间。调度器会根据浏览器的每一帧的时间预算,将任务分割成合适的时间片来执行。

对于不同优先级的任务,调度器会采用不同的策略。高优先级的任务(如用户交互响应)会尽快得到执行,而低优先级的任务(如数据预取)则会在系统空闲时执行。

2、纤维架构(Fiber Architecture)的支持
React的纤维架构是实现并发功能的基础。纤维是一种轻量级的数据结构,每个纤维代表一个组件。在渲染过程中,React可以暂停、恢复和重新调度纤维的渲染。

纤维架构使得React能够在渲染过程中进行中断和恢复,以便在合适的时机处理其他任务。例如,当一个组件的渲染被中断时,React会保存当前的渲染状态,然后在后续合适的时间点继续渲染。

二、React15架构

在 React 15 架构中:

1、 Reconciler(协调器)负责找出变化的组件

reconciler(协调器)采用的是 stack reconciler 解决方案。它在更新子组件时会进行递归操作,且一旦开始更新就无法中断。当组件层级较深时,这种同步的递归更新可能会导致在一帧内无法完成更新,从而使用户交互出现卡顿的情况。为了解决卡顿16版本进行了功能重构。

(一)工作方式

React中可以通过this.setState、 this.forceUpdate、ReactDom.render等API触发更新。
每当有更新发生时,reconciler会做如下工作:
触发更新。

  1. 调用函数组件、或class组件的render方法,将返回的JSX转化为虚拟DOM
  2. 虚拟DOM和上次更新时的虚拟DOM对比
  3. 通过对比找出本次更新中变化的虚拟DOM
  4. 通知Renderer将变化的虚拟DOM渲染到⻚面上

在 React 15 版本中,Reconciler(协调器)的工作方式具有以下特点和原理:

(二)功能

1、 构建虚拟 DOM 树
React 维护了一个虚拟 DOM(Virtual DOM)的概念。在 React 15 中,Reconciler 负责根据组件的定义和状态构建虚拟 DOM 树。每个 React 组件都对应虚拟 DOM 树中的一个节点,包含组件的类型、属性、子节点等信息。

例如,当定义一个简单的 <div> 组件时,Reconciler 会为其创建相应的虚拟 DOM 节点来表示这个组件在虚拟 DOM 树中的结构和属性。

2、 协调更新
当组件的状态或属性发生变化时,Reconciler 会启动更新流程。它会比较变化前后的虚拟 DOM 树,以确定哪些部分需要进行实际的 DOM 操作来更新页面。

例如,当一个按钮组件的文本从“点击我”变为“已点击”时,Reconciler 会识别出这个变化,并确定需要更新对应的 DOM 元素中的文本内容。

3、 管理组件生命周期
Reconciler 在协调过程中还会触发组件的生命周期方法。在 React 15 中,常见的生命周期方法如 componentWillMountcomponentDidMountcomponentWillReceivePropsshouldComponentUpdatecomponentWillUpdatecomponentDidUpdate 等。

比如在组件挂载阶段,componentWillMountcomponentDidMount 会依次被调用,让开发者可以在这些方法中执行一些初始化操作或发送网络请求等。

(三)原理

1、深度优先遍历和递归
Reconciler 采用深度优先遍历的方式来递归地处理虚拟 DOM 树。从根节点开始,依次遍历每个子节点及其子树。

例如,对于如下的组件结构:<Parent><Child1><GrandChild1></GrandChild1></Child1><Child2></Child2></Parent>,它会先处理 Parent 组件,然后是 Child1,接着是 GrandChild1,再回到 Child2

在递归过程中,每个组件会根据自身的 render 方法生成新的虚拟 DOM 子树,然后 Reconciler 继续对这些子树进行处理。

2、 diff 算法比较
在更新阶段,Reconciler 使用 diff 算法来比较新旧虚拟 DOM 树的差异。它会逐个节点地进行比较,检查节点类型、属性、子节点等方面的变化。

如果节点类型不同,React 通常会认为整个子树都发生了变化,会销毁旧的 DOM 节点并创建新的 DOM 节点。例如,旧的虚拟 DOM 节点是 <div>,新的是 <span>,那么整个 <div> 及其内部的子节点都会被替换为 <span> 及其子节点。

如果节点类型相同,会进一步比较属性的变化。例如,检查 classNamestyle 等属性是否有更新,如果有变化,就会相应地更新实际的 DOM 元素的属性。

对于子节点,会通过遍历和比较的方式来确定子节点的添加、删除或移动等操作。

2、Renderer(渲染器)负责将变化的组件渲染到页面上

(一) 同步更新

React 15 的 Reconciler 执行更新是同步的。这意味着当一个 setState 触发更新时,React 会立即开始进行 Reconciliation(协调)Rendering(渲染)过程,直到整个更新过程完成。

虽然同步更新在一些简单场景下比较直观,但在复杂的应用中,如果有大量的计算或长时间的同步操作,可能会导致页面卡顿,因为浏览器在更新过程中无法响应用户交互或进行其他任务。

(二)更新原理图

在这里插入图片描述
图中state.count乘以2之后,Reconciler找出变化的组件交给renderer进行更新,整个过程是同步递归实现的,直到组件都遍历完成。

在 React 16 及以后的版本中,Reconciler 进行了重大的改进,引入了 Fiber 架构,使得更新过程可以被中断和恢复,提高了性能和用户体验。

三、React16架构

1、 Scheduler(调度器)

调度任务的优先级,高优任务进入Reconciler

React Scheduler 的优先级划分主要基于以下几个方面:

一、不同优先级的分类

  1. Immediate Priority(同步优先级)
    这是最高优先级,通常用于处理用户交互等关键操作,比如处理点击事件、键盘输入等。这些操作需要立即得到响应,以提供流畅的用户体验。

    当任务具有同步优先级时,React 会尽可能快地执行它,甚至可能中断正在进行的其他任务来处理它。

  2. UserBlocking Priority(用户阻塞优先级)
    此优先级用于那些会影响用户体验,但不是立即关键的任务。例如,一些数据预取操作,虽然不是立即必需,但如果延迟太久会让用户感觉到卡顿。

    通常会在不影响当前用户交互的情况下尽快执行。

  3. Normal Priority(普通优先级)
    这是默认的优先级级别,适用于大多数常规的更新和渲染任务。比如组件的状态更新导致的重新渲染通常是普通优先级。

    React 会在合适的时机调度和执行这些任务,以平衡性能和响应性。

  4. Low Priority(低优先级)
    用于不太紧急的任务,比如一些后台数据同步或者非关键的日志记录等。

    这些任务可能会在其他更高优先级的任务完成后,或者在系统空闲时才会被执行。

  5. Idle Priority(空闲优先级)
    这是最低的优先级,用于那些可以在任何时间执行,并且不会影响用户体验的任务,比如一些清理操作或者统计信息的收集等。

通常在浏览器空闲时间执行,不会抢占其他任务的执行时间。

2、 Reconciler(协调器)

负责找出变化的组件
React16的Reconciler更新机制发生了变化
在版本15中是递归方式
在版本16中是可以中断的循环过程

function performSyncWorkOnRoot(root) {
  // 开始同步更新根节点
  const finishedWork = workLoopSync();
  // 完成更新后进行提交阶段
  commitRoot(root, finishedWork);
}

function workLoopSync() {
  while (workInProgress!== null && !shouldYield()) {
    performUnitOfWork(workInProgress);
  }
  return workInProgress;
}

function performUnitOfWork(fiber) {
  const next = beginWork(fiber);
  if (next === null) {
    completeUnitOfWork(fiber);
  } else {
    workInProgress = next;
  }
}

workLoopSync是一个同步工作循环函数。它的主要目的是在同步模式下处理工作单元(可能是 React 组件的更新任务)。
循环条件包含两个部分:

  • workInProgress!== null:只要还有未完成的工作(workInProgress不为空),循环就会继续。workInProgress通常代表当前正在处理的 Fiber 节点。
  • !shouldYield():在每一次循环迭代中,会检查是否应该让出执行权(yield)。如果shouldYield()返回false,表示可以继续执行当前的工作,不会中断循环;如果返回true,则表示可能需要暂停当前工作,给其他任务或浏览器一些时间来处理其他事情(例如响应用户输入、渲染动画等)。

例如:在处理一个大型组件树时,如果浏览器的每一帧时间内还有剩余时间来处理更多的更新工作,workLoopSync会继续处理下一个工作单元;如果当前帧的时间已经用尽,shouldYield()可能会返回true,导致循环暂停,等待下一个机会继续执行。

3、Renderer(渲染器)

负责将变化的组件渲染到页面上

在React16中的变化:

ReconcilerRenderer不再是交替工作。当Scheduler将任务交给Reconciler后,Reconciler会为变化的虚拟DOM打上代表增/删/更新的标记
整个SchedulerReconciler的工作都在内存中进行。只有当所有组件都完成Reconciler的工作,才会统一交给Renderer。

在这里插入图片描述
其中红框中的步骤随时可能由于以下原因被中断:

  • 有其他更高优任务需要先更新
  • 当前帧没有剩余时间

由于红框中的工作都在内存中进行,不会更新页面上的DOM,所以即使反复中断,用户也不会看见更新不完全的DOM

四、Fiber架构

以下是关于 React Fiber 的详细介绍:

1、React Fiber 定义

React Fiber 是 React 16 对其核心算法(Reconciler,协调器)进行的一次重写,它是一种新的协调算法和架构模式。目的是使 React 能够更好地处理大型应用程序和更复杂的更新,同时提高应用的响应性和用户体验。
特点:支持状态更新、优先级调度、异步可中断
1. 作为架构来说
之前React15的Reconciler采用递归的方式执行,数据保存在递归调用栈中,所以被称为stack ReconcilerReact16的Reconciler基于Fiber节点实现,被称为Fiber Reconciler
2. 作为静态的数据结构来说
每个Fiber节点对应一个React element,保存了该组件的类型(函数组件/类组件/原生组件…)、对应的DOM节点等信息;
3. 作为动态的工作单元来说
每个Fiber节点保存了本次更新中该组件改变的状态、要执行的工作(需要被删除/被插入页面中/被更新…);

2、原理解析

  1. 任务分割与优先级处理
    React Fiber 将更新任务分割成一个个小的工作单元(Fiber 节点)。每个 Fiber 节点代表一个组件或者 DOM 节点的更新任务。

    引入了优先级的概念,不同的更新任务可以有不同的优先级。高优先级的任务(如用户交互产生的更新)可以中断低优先级的任务(如数据预取后引发的更新),优先得到处理。

  2. 可中断与恢复
    在执行更新任务时,React Fiber 采用了可中断的循环方式。通过 requestIdleCallback(在不支持的浏览器中使用 setTimeout 模拟)等机制,React 可以在每一个时间片(大约 5ms)内执行一部分任务。

    如果在一个时间片内没有完成当前任务,它会保存当前的状态,让出主线程的控制权,等待下一个时间片继续执行,从而实现可中断与恢复。

  3. Fiber 节点结构
    Fiber 节点包含了多个重要的属性:

    • return:指向父节点,用于在遍历树时回溯。
    • child:指向第一个子节点。
    • sibling:指向下一个兄弟节点。
    • tag:表示节点的类型,如函数组件、类组件、原生 DOM 元素等。
    • pendingPropsmemoizedProps:分别表示即将应用的属性和已经应用的属性。
  4. 双缓冲树
    React Fiber 使用了双缓冲的 Fiber 树机制。在更新过程中,会构建一棵新的 Fiber 树(称为“workInProgress 树”),同时保留旧的 Fiber 树(“current 树”)。

当新树构建完成后,通过指针切换,瞬间将新树变为当前树进行渲染,避免了一次性大规模的 DOM 操作,提高了更新的效率和性能。
在这里插入图片描述

(1)首次执行
首次执行ReactDOM.render会创建fiberRootNode(源码中叫fiberRoot)和rootFiber。其中fiberRootNode是整个应用的根节点,rootFiber是所在组件树的根节点;
(2)render阶段
根据组件返回的JSX在内存中依次创建Fiber节点并连接在一起构建Fiber树,被称为workInProgress Fiber
(3)alternate阶段
此时workInProgress fiber已经构建完成,fiberRootNodecurrent指向了workInProgress fiber
(4)update阶段
假设p元素更新,这会开启一次新的render阶段并构建一棵新的workInProgress Fiber 树,且会尽可能复用现有的current Fiber
(5)alternate阶段
workInProgress fiber在更换完后,fiberRootNodecurrent指针更换

3、实例分析

假设一个简单的 React 应用,包含一个父组件和多个子组件:

import React, { useState } from 'react';

function ChildComponent({ index }) {
    return <div>Child {index}</div>;
}

function ParentComponent() {
    const [count, setCount] = useState(0);

    const handleClick = () => {
        setCount(count + 1);
    };

    const childComponents = [];
    for (let i = 0; i < 10; i++) {
        childComponents.push(<ChildComponent key={i} index={i} />);
    }

    return (
        <div>
            <button onClick={handleClick}>Increment</button>
            {childComponents}
        </div>
    );
}

export default ParentComponent;

当用户点击按钮触发 setCount 状态更新时:

  1. React Fiber 开始协调更新过程。
  2. ParentComponent 根节点对应的 Fiber 节点开始,进入工作循环。
  3. 遍历子组件,为每个 ChildComponent 创建或更新对应的 Fiber 节点。
  4. 如果在处理某个子组件的过程中,时间片用完或者有更高优先级的任务进来,React Fiber 会暂停当前工作,保存当前状态,等待下一次继续执行。
  5. 所有组件的 Fiber 节点处理完成后,构建出完整的 workInProgress 树。
  6. 最后,将新的 workInProgress 树切换为 current 树进行渲染,用户界面得到更新。

总之,React Fiber 带来了更高效、更灵活的更新机制,使 React 能够更好地应对复杂的应用场景和用户需求。

五、任务调度循环和fiber构造循环区别

1、定义

(1)任务调度循环
源码位于Scheduler.js, 它是react应用得以运行的保证, 它需要循环调用, 控制所有任务(task)的调度.

(2)fiber构造循环
源码位于ReactFiberWorkLoop.js, 控制 fiber 树的构造, 整个过程是一个深度优先遍历.

这两个循环对应的 js 源码不同于其他闭包(运行时就是闭包), 其中定义的全局变量, 不仅是该作用域的私有变量, 更用于控制react应用的执行过程.

2、区别

任务调度循环
主要负责对更新任务进行调度和优先级管理。
任务调度循环是以二叉堆为数据结构(详见react 算法之堆排序), 循环执行堆的顶点, 直到堆被清空.
任务调度循环的逻辑偏向宏观, 它调度的是每一个任务(task), 而不关心这个任务具体是干什么的(甚至可以将Scheduler包脱离react使用), 具体任务其实就是执行回调函数performSyncWorkOnRoot或performConcurrentWorkOnRoot.

fiber构造循环
是以树为数据结构, 从上至下执行深度优先遍历(详见react 算法之深度优先遍历).
fiber构造循环的逻辑偏向具体实现, 它只是任务(task)的一部分(如performSyncWorkOnRoot包括: fiber树的构造, DOM渲染, 调度检测), 只负责fiber树的构造.
每个 Fiber 节点代表一个组件或者 DOM 节点的更新任务,Fiber 构造循环通过遍历这些节点来协调组件的更新和渲染。

3、联系

任务调度循环和 Fiber 构造循环在 React 中是紧密关联的,它们协同工作来实现高效的组件更新和页面渲染:

一、任务触发与传递

  1. 任务调度循环是更新任务的入口和管理者。当有更新事件发生(如用户交互、状态改变、网络数据获取等),任务调度循环首先感知到这些事件并将它们转化为相应的更新任务。

  2. 这些更新任务会被分配优先级,并根据优先级排队等待执行。当轮到某个任务执行时,任务调度循环会将任务传递给 Fiber 构造循环,启动组件树的更新过程。

    例如,用户点击一个按钮触发了组件的状态更新,任务调度循环会捕获这个事件,将其包装成一个更新任务并确定其优先级。然后,当条件合适时,它会将这个任务传递给 Fiber 构造循环来开始处理组件树的更新。

二、时间片与可中断性协调

  1. 任务调度循环利用时间片的概念来管理任务的执行时间。它会根据浏览器的空闲时间和帧刷新率等因素,为每个任务分配一个时间片(通常是几毫秒)。

  2. Fiber 构造循环在执行过程中会遵循任务调度循环分配的时间片。如果在一个时间片内无法完成当前的组件更新工作,Fiber 构造循环会暂停当前的工作,保存当前的状态和进度。

  3. 任务调度循环会在下一个合适的时间片再次启动 Fiber 构造循环,继续之前未完成的工作。这样的可中断性和时间片管理机制确保了页面在更新过程中仍然保持响应性,不会因为长时间的 JavaScript 执行而导致卡顿。

    比如在更新一个复杂的组件树时,Fiber 构造循环可能在处理一个深层嵌套的组件时时间片用完。此时,它会暂停工作,任务调度循环会在后续的时间片中再次安排它继续执行。

三、优先级处理的一致性

  1. 任务调度循环和 Fiber 构造循环都遵循相同的优先级策略。高优先级的任务会在低优先级任务之前得到处理,以确保关键的用户交互和紧急的更新能够及时响应。
  2. 任务调度循环在任务排队时会根据优先级进行排序,而 Fiber 构造循环在遍历组件树时也会优先处理高优先级的组件更新。
    例如,一个用户输入的即时响应任务(高优先级)和一个后台数据预取后的组件更新任务(低优先级),任务调度循环会首先安排高优先级任务执行,然后再考虑低优先级任务。在 Fiber 构造循环中,也会优先处理与高优先级任务相关的组件更新。

四、共同服务于页面渲染和用户体验

  1. 任务调度循环和 Fiber 构造循环的最终目标都是为了实现高效的页面渲染和良好的用户体验。

  2. 任务调度循环通过合理的任务管理和优先级调度,确保重要的更新任务能够及时执行,同时避免任务堆积和页面卡顿。

  3. Fiber 构造循环通过高效的组件树更新和可中断的工作方式,使得页面在更新过程中能够保持响应,减少用户感知到的延迟和卡顿。

    无论是在处理频繁的用户交互还是大规模的组件树更新,这两个循环相互配合,使得 React 应用能够在各种复杂情况下都能提供流畅的用户体验。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2037861.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Android Basis - 密钥和ID认证

书读百遍其义自现&#xff0c;知识点多复习&#xff0c;看到的越多&#xff0c;理解的也越是深刻。也许此时我看到的点是点&#xff0c;十天半个月之后回头看时可能就是新的点或者线了&#xff0c;写博客也是&#xff0c;越写越深刻。 遇到KeyAttestation在gms中的错误 在cts…

EVAL长度突破限制

目录 突破15位限制 代码 绕过方式 第一种&#xff08;使用echo执行&#xff09; 第二种&#xff08;使用file_get_content追加文件后进行问件包含&#xff09; 第三种&#xff08;使用usort可变长参数&#xff09; 突破7位限制 第一种&#xff08;可以使用>创建文件…

whistle非常好用的抓包工具

文档&#xff1a; https://wproxy.org/whistle/install.html 总结 这个工具的界面非常好理解&#xff0c;易于使用。 前端开发过程中&#xff0c;经常需要抓包看数据&#xff0c;mock请求数据&#xff0c;mock响应数据&#xff0c;代理线上资源等 这个工具统统可以满足 一、…

【C++二分查找 贪心】792. 匹配子序列的单词数

本文涉及的基础知识点 C二分查找 贪心 LeetCode792. 匹配子序列的单词数 给定字符串 s 和字符串数组 words, 返回 words[i] 中是s的子序列的单词个数 。 字符串的 子序列 是从原始字符串中生成的新字符串&#xff0c;可以从中删去一些字符(可以是none)&#xff0c;而不改变其…

基于PCA-BP的数据多变量回归预测 Matlab代码(多输入单输出)[可显示原始特征贡献率+贡献率排序+累计贡献率]

基于PCA-BP的数据多变量回归预测 Matlab代码&#xff08;多输入单输出&#xff09;[可显示原始特征贡献率] 1.首先通过主成分分析PCA将数据进行降维&#xff0c;会显示原始特征对应的贡献率(不是贡献率排序&#xff0c;不会让你对应不到对应特征)&#xff0c;选取要求为累计贡…

RAG 系列之二:PDF 文件的解析

在 RAG&#xff08;检索增强生成&#xff09;简介的流程图中&#xff0c;有一个环节是检索向量数据库&#xff08;下图中红色框标识的部分&#xff09;。向量数据库存储了外部知识库经过向量化处理的内容。在检索之前&#xff0c;我们首先需要创建向量数据库&#xff0c;而创建…

虚拟化—XenServer安装教程详细(附客户端连接)

&#x1f3e1;作者主页&#xff1a;点击&#xff01; &#x1f427;Linux基础知识(初学)&#xff1a;点击&#xff01; &#x1f427;Linux高级管理防护和群集专栏&#xff1a;点击&#xff01; &#x1f510;Linux中firewalld防火墙&#xff1a;点击&#xff01; ⏰️创作…

积鼎 VirtualFlow 案例|高精度工程雾化模型,优化离心旋流喷嘴雾化效果

雾化喷嘴已广泛渗透于航空航天、车辆工程、医药制造、精密生产、食品加工、环境保护以及现代农业等众多工业领域&#xff0c;成为提升各行业生产效率与性能的关键工具。因此&#xff0c;雾化喷嘴的仿真技术显得尤为重要&#xff0c;通过准确模拟喷嘴的雾化过程&#xff0c;帮助…

idea项目注册在nacos错误:Cannot determine local hostname

一开始想把项目注册在nacos上&#xff0c;启动报错是这样的&#xff0c;而且yml文件也不生效&#xff0c;因为默认端口是8080&#xff0c;我在yml文件中写了8081没用&#xff0c;正好nacos的配置也在yml文件中。各种百度&#xff0c;各种依赖添加删除&#xff0c;反复启动没用 …

Redis7-分布式锁

目录 基本原理 分布式锁的实现 基于Redis的分布式锁 Redis分布式锁误删 分布式锁的原子性问题 基于Redis的分布式锁优化 Redission概述 Redisson入门 Redisson可重入锁原理 ​编辑 Reddisson锁重试和WatchDog机制 Redisson分布式锁原理 Redission的MultiLock原理 …

《江南:在爱开始的地方等你》定档9月15日,愿有情人终成眷属

由康锐原创小说《月落姑苏》改编&#xff0c;并由康锐导演、编剧&#xff0c;赖雨濛、刘冬沁领衔主演、朱丹妮、王沛为、金巧巧、阎青妤、李菁菁、苇青等共同主演的电影《江南&#xff1a;在爱开始的地方等你》官宣定档中秋。 影片讲述了陆骁&#xff08;刘冬沁饰&#xff09;…

Excel VBA批量获取文件夹内文件名及重命名文件教程

在本文中&#xff0c;我们将介绍如何使用Excel VBA宏来批量获取文件夹内的文件名&#xff0c;并将其输出到Excel单元格区域。此外&#xff0c;我们还将展示如何根据Excel中的列表批量重命名这些文件。 一、批量获取文件夹内文件名 首先&#xff0c;我们需要编写一个VBA宏来列出…

【《Kafka 入门指南:从零基础到精通》】

前言&#xff1a; &#x1f49e;&#x1f49e;大家好&#xff0c;我是书生♡&#xff0c;本阶段和大家一起分享和探索KAFKA&#xff0c;本篇文章主要讲述了&#xff1a;消息队列的基础知识&#xff0c;KAFKA消息队列等等。欢迎大家一起探索讨论&#xff01;&#xff01;&#x…

用7EPhone云手机进行TikTok的矩阵运营

“根据市局机构Statista发布的报告显示&#xff0c;截至2024年4月&#xff0c;TikTok全球下载量超过49.2亿次&#xff0c;月度活跃用户数超过15.82亿。TikTok的流量受欢迎程度可想而知&#xff0c;也一跃成为了全球第五大最受欢迎的社交APP。” 人群密集的地方社区也是适合推广…

《pygame游戏开发实战指南》第八节 Sprite类和Group类

Sprite(精灵)是游戏中一个非常重要的概念。在游戏开发中&#xff0c;‌Sprite指的是一个可以移动、‌旋转或变换的二维图像&#xff0c;‌它负责管理游戏中的图像元素&#xff0c;‌使得开发者可以轻松地在游戏中创建各种动态效果和角色。‌pygame.sprite模块提供了Sprite类和G…

分类预测|基于鲸鱼优化-卷积-长短期记忆网络-注意力数据分类预测Matlab程序 WOA-CNN-LSTM-Attention

分类预测|基于鲸鱼优化-卷积-长短期记忆网络-注意力数据分类预测Matlab程序 WOA-CNN-LSTM-Attention 文章目录 前言分类预测|基于鲸鱼优化-卷积-长短期记忆网络-注意力数据分类预测Matlab程序 WOA-CNN-LSTM-Attention 一、WOA-CNN-LSTM-Attention模型1. 鲸鱼优化算法&#xff0…

产品经理的具体职责有哪些?

产品经理作为产品团队的核心角色&#xff0c;负责从概念到市场发布的整个过程&#xff0c;确保产品能够满足用户需求&#xff0c;实现商业目标。其工作职责广泛且深入&#xff0c;涵盖了产品规划、设计、开发、运营、推广等多个方面。以下是详细的工作职责描述以及产品经理的核…

一文彻底搞懂Transformer - 注意力机制

Transformer 一、注意力机制 Seq2Seq 注意力机制目标 Attention模块的主要作用是确定在给定上下文中哪些嵌入向量与当前任务最相关&#xff0c;并据此更新或调整这些嵌入向量的表示。 Transformer注意力机制 注意力机制案例 注意力机制计算公式 生成Q、K、V向量&#xff1a;对…

智能升降晾衣架:NRK3301语音识别模块ic让家务变得更轻松

对于经常做家务的人来说&#xff0c;洗衣服和晾衣服是一件非常耗费体力和时间的任务。传统的晾衣架安装在了一个固定的高度&#xff0c;挂衣服和取衣服需要通过撑衣杆来晾取衣物&#xff0c;即便是电动升降的晾衣架&#xff0c;也需要人手动去操作&#xff0c;增加了工作量。然…

Vue 项目中导入文件时如何默认找寻该文件夹下的 index.vue 文件

文章目录 需求分析 需求 如下图&#xff0c;在Vue 项目中导入 frequencyChange 文件夹时如何默认找寻该文件夹下的 index.vue 文件 分析 确保项目结构和命名约定 首先&#xff0c;确保你的 Vue 单文件组件按照约定命名&#xff0c;例如&#xff1a; components/Example/inde…