当前位置: 首页 > news >正文

打造高性能在线电子表格:WebGL 渲染引擎 Kola2d 自研之路

导读:本文主要阐述了 Docs 在线表格为打造极致渲染性能所做的关键优化和过程思考,作为首个在在线电子表格领域自研基于WebGL渲染引擎的「吃螃蟹」者,整个过程面临诸多不确定性与挑战,Kola2d 的整体设计在此期间也经历了几轮推倒重来,最终的落地方案经过了多番探索与实践,希望给到对WebGL渲染引擎及高性能表格感兴趣的同学一些参考。

一、背景

Docs 电子表格是一款快手效率工程出品的自研协同办公产品,在快手内部被广泛使用:

图片

这类在线表格通常对性能有极高要求,需要面临以下挑战:

  • 多人实时协作:在线电子表格通常支持多用户同时编辑,这意味着系统必须能够快速处理多个用户的操作并实时更新界面,确保所有用户看到的数据是一致的。

  • 海量数据:团队有大量数据存储在在线表格上,在线表格需要能够高效地加载、渲染和操作这些数据。例如,进行复杂的计算、排序和筛选等操作时,性能要求就更高。

  • 复杂功能:现代在线表格通常集成了类 Excel 丰富的功能,如公式计算、图表生成、权限管理等。这些功能对系统性能提出了更高的要求,因为它们需要实时计算和渲染。

为提高 Docs 在线表格渲染性能在前期我们已经做过很多努力和尝试,其核心渲染引擎也由最初的基于 DOM 的渲染变更为了 Canvas 2D 渲染,这在一定程度上提高了 Docs 在线表格的渲染性能,但随着用户数据的增长和使用场景的扩充,我们依旧收到不少用户反馈 Docs 在线表格卡顿,特别是大表格、多人协同场景。

为彻底解决 Docs 在线表格的渲染卡顿问题,追求极致的渲染性能,使电子表格可以适配更多数字作业场景,我们对在线表格进行了深度改造,并自主研发了 WebGL 渲染引擎 Kola2d,最终使得 Docs 在线表格能以 50+FPS 的帧率渲染拥有百万单元格的超大表格。为打造下一代高性能电子表格配置了「核动力」。

当前,在线表格通常采用 DOM 或 Canvas2D 进行渲染,但 DOM 渲染已基本被淘汰。Kola2d 渲染引擎创新性地引入了 WebGL,这在在线表格渲染领域尚属首创,并在此基础上设计了多种性能提升策略。本文将深入探讨 Docs 在线表格的内部,揭示 Kola2d 在提升渲染性能方面的关键策略和技术实现。

二、为什么是WebGL

Canvas 2d 有自己的性能瓶颈,在大量级数据渲染上很显吃力。经过调研,我们将目光聚焦到另一种方案:WebGL。WebGL 在渲染大量级数据的优势这主要体现在以下方面:

  • 硬件加速:WebGL 是基于 OpenGL ES 的,它可以直接利用 GPU 的强大计算能力进行渲染。因此,它能够处理更复杂的图形和更高效的图形渲染,而 Canvas 2D 则主要依赖于 CPU 渲染,性能相对较低。

  • 并行处理:WebGL 可以利用 GPU 的并行处理能力,能够同时处理大量的顶点和片元,这对于需要大量图形计算的应用(如游戏、数据可视化等)非常重要。Canvas 2D 则通常是顺序处理,效率较低。

在前期做也对 WebGL 渲染做了可行性测试,结果显示 WebGL 渲染性能显著强于 Canvas 2d:

10万单元格

100万单元格

WebGL

60FPS

60FPS

Canvas2d

10FPS

卡死

通过分析市面上的 WebGL 框架优缺点,我们最终决定自研 WebGL 渲染引擎 Kola2d

图片

三、Kola2d

Kola2d 职责范围

在设计 Kola2d 渲染器之前,我们对 Docs 在线表格的整体业务做了下梳理,将 Docs 在线表格分为了两层,这使得 Docs 在线表格有清晰的职责划分:

  • 业务层:业务层专注业务封装
  • 渲染层:渲染层专注渲染,渲染层即 Kola2d

业务层数据转换

业务层和渲染层相对隔离,业务层的数据需要做转换然后提交给 Kola2d。我们将业务层提交的数据起了一个名字:显示对象树。当然,业务层不仅仅显示对象的生产者,同时它需要有一个合理的结构,方便后续进行维护和扩展。

业务层结构

业务层被进一步细分,秉持单一数据流原则更好控制内容的变更:

图片

  • 基础数据:表格基础数据

  • 数据模型:将基础数据做转换后会生成数据模型

  • 视图模型:数据模型的变更会触发视图模型的变更

  • 显示对象树:视图模型变更后会触发更新显示对象树,它就是业务层的最终产出,后面会提供给 Kola2d 消

显示对象树结构

显示对象树即表格内容的抽象呈现,表格内容大体可分为视图、装饰、插件这几类,每个类下面又有具体的细分:

图片

将视图、装饰、插件做抽象得到三大业务类,将业务类做组装并形成显示对象树的结构:

图片

Grid 即显示对象树,Grid 主要由视图层和装饰层组成:

  • 视图层有多个视图,每个视图内可以嵌入多个插件

  • 装饰层有多个装饰,每个装饰可以嵌入多个插件

Grid 目前只是一个基础的骨架,我们还需要给里面填充内容,Grid 的内容分为两种:

  • 内置内容:Grid 初始化时就会自动订阅视图模型,然后生成内容

  • 嵌入内容:由外部通过插件的形式嵌入进 Grid 里

看到这里你也许会疑惑,难道我们可以随意自定义显示对象树吗?答案当然是否定的!

Kola2d 内部提供以下基础的显示对象,几乎表格页面的所有内容都可以用这些对象表示:

图片

业务层生成的显示对象要么继承自这些对象,要么直接使用这些对象,所以它才能被 Kola2d 识别并最终渲染出来。

Kola2d高效渲染的原理

Kola2d 的核心目标是能以 50+ FPS 的标准渲染百万单元格级的大表格,同时满足其多人协同场景下的流畅性。

处理百万单元格

我们前面做的性能测试显示 WebGL 底层是完全能扛住 100 万单元格的压力的,但我们的开销并不仅仅是在 GPU 上, CPU 也要处理大量的前置工作,比如排版、生成各种数据模型等,这往往会耗费很大的开销,让页面长时间处于无响应状态。前面提到 Kola2d 的角色仅仅是渲染,它并不负责排版这些前置操作,想要真正实现渲染 100 万单元格需要业务层和渲染层共同协作。

其实不管是大表格还是多人协同场景下的表格用户的关注点都在视图区内,如果视图区内的内容能够快速的呈现出来那么对于用户来说页面就是流畅的。那么可以换一种思路,虽然要渲染 100 万单元格,但我们是否只用在页面真正需要呈现这些内容时才去做对应的前置操作?

答案是可以的,只要业务层能确定目前视图区应该展示什么内容,那么就可以只准备视图区内的数据。但是想要确定视图区应该展示什么内容,就必须要先对就要对内容做排版,然后才能确哪些内容应该展示到视图区。Kola2d 虽然不直接负责排版,但是它对外提供了一个 FormattedText 的文字排版包,而文字排版又是页面排版最复杂的部分,它可以轻松实现文字的度量和排版,它内部会缓存排版结果,遇到样式相同的文字时会直接使用缓存结果,进而加快排版速度:

图片

业务层可以直接调用 FormattedText 做文字排版,有了这个排版包的协助,业务层就可以轻松计算视图区排版结果。

但是,视图区外的数据会影响视图区内数据的相对位置,比如现在我在第 100 行的位置时,前面的数据会影响我后面的相对位置:

图片

因此,业务层启用了一个新的策略,视图区外的行列使用默认宽高,当它需要展示到视图区时再区排版它的真实宽高,然后将排版结果缓存。

我们最终吐给 Kola2d 的数据是视图区内的单元格。当然我们也可以将 100 万单元格数据吐给 Kola2d,Kola2d 内部也有对应的优化策略,它内部也提供了一套剔除机制,会将不在视图区的单元格剔除,仅渲染视图区部分:

图片

但我们并不鼓励给 Kola2d 吐太多的数据,Kola2d 内部也有 CPU 计算,光是循环 100 万条数据,CPU 耗时就能达到 10ms 左右,我们希望尽量减少 CPU 的消耗,这样 CPU 可以做更多其它的事情

 处理多人协同

多人协同场景下的表格内容变更会非常频繁,假设有几百个人同时编辑表格,那么页面将疲于奔命去处理这些变更,所以我们需要尽可能的去减少单次变更所需要的时间。

页面上用户看到的内容就是一个个像素,页面的变更到最终变成为对应的像素数据有更专业的称呼:光栅

对于渲染引擎来说,光栅的开销是非常大的,就拿  Chrome 来说,所谓的硬件加速,就是把光栅的操作交给 GPU 来执行:

图片

尽管有 GPU 做光栅,但这还远远不够,Chrome 做了大量工作来减少每次光栅的数量:

  • 由 main 线程对对页面的绘制做分层,生成多层的绘制指令

  • 由 impl 线程做合成,分片等,对光栅区域做优先级区分,优先光栅高优的区域,同时光栅后结果是会做缓存的,避免重复光栅

  • 如果页面变动可以根据前面已经生成的结果做计算,然后仅光栅需要光栅的部分

从 Chrome 得到启发,kola2d 的核心架构思路即:

  • 尽量减少光栅

  • 尽量使用 GPU 做光栅

  • 尽量利用光栅缓存

到这里,或许你会有一个疑问,既然借鉴浏览器内部设计,那为什么不直接用 DOM?

其实最初表格就是直接用 DOM 渲染的,小表格还好,一旦遇到数万行甚至数十万行表格时,浏览器就显得吃力,同时多人协同时频繁变更 DOM 使得页面卡顿非常严重。因此后期做了一版优化,将 DOM 改 Canvas2d 渲染。

但这并不代表浏览器不行,而是在我们表格的这个场景下浏览器比较吃力而已。Kola2d 吸收了 Chrome 内部的一些优秀的设计理念引入了诸如分片、光栅结果缓存等概念,同时结合表格自身的使用场景设计了诸如剔除、视图区光栅等功能。

减少光栅的策略

对于减少光栅,我们不得不提到 Chrome 的分片,Chrome 分片主要用于以下:

  • 减少光栅:页面做分片后,仅对有内容变更的分片需要做光栅

  • 控制内存:分片可以帮助控制内存,对于不在视图区的分片或者离视图区比较远的分片,如果内存告急的时候可以被释放掉

Kola2d 的分片思想也是借鉴了  Chrome,但 Kola2d 的分片跟 Chrome 略有不同,Chrome 是排版完整个页面后再以页面维度做的分片,而 Kola2d 仅以单元格维度做的分片:

图片

Kola2d为什么以单元格维度做分片?

图片

表格的最小变更范围为一个单元格,以单元格维度做分片,就能保证假如一个单元格内容发生变更那么就仅仅重新光栅化这一个单元格。

这在多人协同场景下十分有利,我们可以最大化的减少需要重新光栅的分片的数量,提高渲染性能。

同时由于业务层只关注视图区,就算多人协同修改了视图区外的数据,这也不会影响到视图区内,进一步减少了额外的损耗。

有了分片,我们可以仅光栅内容变更的单元格,其它单元格直接用缓存的光栅数据就可以了。

但假设协同人数实在太多,那么单位时间要处理的变更也就越多,就算我们把性能做得再极致那么还是会出现卡顿。因此,来自协同者的变更我们并不会立马处理,而是把它放入一个队列中,然后定时到消息队列里取一批消息做处理:

图片

光栅的过程

当某个分片内容发生了变更,我们需要对它重新做光栅,Kola2d 的位图系统应运而生。位图系统会把分片转换成对应的绘制指令,并最终转换成像素数据存到资源管理器。

图片

WebGL 只能绘制点、线、三角形,这意味着页面的所有内容都需要做对应的转换。对于图形这种方式还好,但是对于文字来说这种方式就变得比较吃力,比如下面的字体需要解析其路径信息然后绘制路径并描边:

图片

Chrome GPU 加速的本质就是把图形绘制操作交给在 GPU 进程的 Skia 来绘制,那么也引发了一个思考,我们是否也可以调用 GPU 上的 Skia 来做图形和文字绘制?

其实,目前很多主流浏览器都支持对 Canvas 2d 做硬件加速:

  • Chrome 13

  • Firefox 4

  • Internet Explorer 9

  • Opera 11

  • Safari 5

所以我们可以使用 Canvas 2d 当作一个媒介,前面所说的绘制指令最终都会变成 canvas 绘制指令,最终由底层的 GPU 将绘制指令转换成像素,然后把 Canvas 2d 当作纹理上传给 GPU。

Canvas 2d 不支持 GPU 光栅怎么办?

浏览器并不一定会对 Canvas 2d 做硬件加速,这种情况下我们仍然可以使用 Canvas 2d 做光栅,由于我们实现了分片以及光栅化结果缓存,即使 Canvas 2d 不支持 GPU 加速,我们也可以借由缓存来极大减少页面需要光栅化的数量从而提升性能。

光栅管理

前面提到光栅缓存,我们为Kola2d 设计了一个专门的类用于管理这些光栅后的数据即资源管理器,它主要提供以下功能:

图片

资源代表每个分片需要的内存已经内存对应的像素数据。

位图管理器在对分片做光栅化的时候会先计算分片需要多少资源内存,然后向资源管理器做申请对应的大小,当光栅化完毕后,就会将像素数据写入到对应的内存地址。资源管理器会对它名下的所有资源做统一的管理,本小节不会对资源管理器 API 做讲解,反之会重点介绍它内部的管理功能。

资源优先级管理

资源管理器的空间是有限的,而众所周知像素占用的内存又比较高,我们需要及时清理那些不需要的资源。Chrome 为了实现这一点将分片加了优先级:

图片

越靠近视图区那么分片所属的资源优先级就会越高。

Kola2d 资源管理器不会对资源做这么细力度的控制,而是在每一次 requestAnimation 周期里,如果执行了渲染,那么 updateId 就会更新,这样的计算机制可以保证,离视图区越近那么其优先级就越高,对于那些非视图区的资源,会根据优先级及时做释放:

图片

资源内存管理

资源管理器的内存使用率需要保持在一个合理的水平,内存不够就要及时清理内存。由于资源的优先级是被计算好的,当内存告急时很容易就知道那些资源需要被清理。

一个分片会占据一个资源内存,处于 Viewport 里的显示对象所拥有的资源内存 updateId 值最高,离 Viewport 越远 udpateId 越低,在每一个渲染周期里,会清理这些 updateId 低的资源:

图片

资源权限管理

Kola2d 资源管理器对资源的更新有严格的限制,比如你申请了 16 X 16 的像素区域的资源时,你写入像素的范围就不能超过这个大小,这是为了防止误操作到其它资源。

因此,每一次像素写入操作都必须先申请写入权限,操作完毕后关闭权限,关键代码如下:

图片

这样做还有另外一个好处,即可以追踪哪些资源被更新了,然后仅将变更的资源上传到 GPU。

页面合成

通过前面的处理,现在分片有了,分片的光栅化数据也有了,我们需要把这些光栅化的数据做组装,然后将它提交给 GPU 最终显示到页面上,Kola2d 的着色器就专门负责这项职能:

图片

每个单元格分片都有一个对应的 Draw Quad,Draw Quad 包含了单元格分片的屏幕位置以及它对应的像素位图的内置地址,这些 Draw Quad 会被放进一个 Array Buffer 中然后提交给 GPU,最终展示给用户。

得益于 WebGL,我们可以直接跟 GPU 打交道,这块儿的耗时几乎可以忽略不计。

四、额外优化

通过上文,我们对 Kola2d 是如何实现高效渲染有了初步的认知。为了进一步提升渲染性能,我们还做了很多额外的工作,结合实际业务场景,精细地设计各种策略,其基本原则是,尽可能的最小化更新任务,每次只变动真正需要重新的部分。

对象复用

由于我们只会渲染视图区域内的,随时有可能出现一部分单元格需要新增,一部分单元格需要删除,比如在滚动或者增删行列的场景下。创建单元格和销毁单元格都有一定开销,为此删除的单元格会被回收到回收池里,下次需要创建单元格时会优先复用回收池里的单元格。

图片

对象合并

样式相同的对象,虽然形状不一样,但是可以做合并处理,减少显示对象树的体积同时减少排版时间。

图片

排版优化

在整个渲染过程中,除了真正的绘制任务,还有很大一部分耗时在排版阶段

排版的主要任务是根据行列信息,滚动位置等确定单元格在屏幕中的位置。由于单元格是有内容的,其展示的真实行高与模型行高可能不一致,我们需要对单元格内部的文字进行排版才能得到最终的高度。这个过程非常耗时,为此我们也采用了一系列的手段来优化排版性能。

精准标脏

导致表格重新渲染的原因很多,频率也很高,然而,并非所有操作都需要触发排版,也可能只需要局部排版而非全局排版。考虑到排版是一个耗时较长的任务。我们借鉴浏览器的实现,结合表格实际业务场景,设计了一套标脏更新机制,在不同场景下进行精准标脏。每次绘制前会检查脏区,以避免任何不必要的更新。

图片

同样标脏也是一种惰性更新策略,只有真正需要使用数据的时候才会执行任务,避免了大范围频繁操作下贪婪更新可能会造成的性能影响。

异步分片

一个在线表格可能有数十万乃至百万单元格,为了保证性能,我们默认只会排版并绘制视野范围内的单元格。然而在滚动等场景下,会有大量新的单元格不断出现在视野中,需要执行排版任务,会延长页面真正显示的时间,造成卡顿掉帧。

针对这一问题,我们借鉴经典的异步分片的思想,将排版任务拆分到行,利用浏览器运行的空闲时间异步执行,并缓存排版计算过程中的关键结果,排版后的内容会取消标脏,在后续滚动过程中无需再次执行排版任务。

图片

文本排版优化

最后让我们来到文本排版任务本身,看看有没有优化的空间

文本排版主要发生在自动换行场景下,其算法可概述为,

  • 根据 unicode 断行算法,找到断行可能发生的位置,

  • 逐个检查断行位置,计算文本累积的宽度,如果可用空间不够就开始新的一行。

图片

该过程的主要耗时在文本测量阶段,在非 dom 场景下,我们依赖 ctx.measureText 方法测量文本宽度。由于字符在不同组合下的宽度是不一致的,不能单独将宽度相加,必须以组合的形式进行测量。目前比较普遍的优化方案是采用二分法(如 Konva Text ),但二分过程中会存在重复测量情况,且测量耗时是跟文本长度成正比的,在文本较长时表现也不够好。这里我们借鉴了 Chrome 浏览器的实现,结合表格实际场景,进行了如下的优化:

  • 根据可能发生断行的位置预先对文本进行分词,缓存分词以及单词宽度测量的结果,以便在后续排版任务中复用。

  • 当单词仅含有单个中文字符时是等宽的,可以使用预设标准字符的测量结果,也无需重复测量。

图片

由此,我们大大减少了文本排版耗时,经评测,相较于 Knova ,Kola2d 文本排版在长文本及中文场景下,有明显的性能优势。

图片

最后,我们会对单元格变更原因也进行归类,力求做到最小化精准排版

  • 当排版无关属性(如单元格背景色)发生变更时,不会触发文本排版任务。

  • 当排版相关属性(如单元格layout)发生变更时,分词和测量结果均从缓存中读取,仅重新进行排版计算。

  • 当单元格内容发生变更时,重新进行分词、测量和排版,复用部分缓存的测量结果。

本文作者:快手效率工程部

相关文章:

打造高性能在线电子表格:WebGL 渲染引擎 Kola2d 自研之路

导读:本文主要阐述了 Docs 在线表格为打造极致渲染性能所做的关键优化和过程思考,作为首个在在线电子表格领域自研基于WebGL渲染引擎的「吃螃蟹」者,整个过程面临诸多不确定性与挑战,Kola2d 的整体设计在此期间也经历了几轮推倒重…...

深入理解WPF中的命令机制

Windows Presentation Foundation(WPF)是微软推出的一种用于构建桌面客户端应用程序的技术。它被认为是现代Windows应用程序的基础,具有强大的图形和媒体处理能力。在WPF中,“命令”是一个重要的概念,它为应用程序开发…...

基础算法(6)——模拟

1. 替换所有的问号 题目描述: 算法思路: 从前往后遍历整个字符串,找到问号之后,尝试用 a ~ z 的每一个字符替换即可 注意点:需考虑数组开头和结尾是问号的边界情况 代码实现: class Solution {public …...

2025年广西高考报名流程图解(手机端)

广西 2025 年高考报名时间已经确定啦,从 2024 年 10 月 21 日开始,到 10 月 31 日 17:30 结束 💻【报名路径】 有电脑端和手机端两种选择哦。 电脑端:登录 “广西招生考试院” 网站(https://www.gxeea.cn&#xff0…...

十、结构型(外观模式)

外观模式(Facade Pattern) 概念 外观模式(Facade Pattern)是一种结构型设计模式,旨在为复杂子系统提供一个简化的统一接口。通过外观模式,客户端可以与子系统交互,而无需了解子系统的内部复杂性…...

10.12Python数学基础-矩阵(上)

矩阵 1.矩阵定义 1.1 矩阵的定义 矩阵是由一组数按照矩形排列而成的数表。矩阵通常用大写字母表示,例如 AA、BB 等。矩阵中的每个数称为矩阵的元素或元。 一个 mn的矩阵 AA 可以表示为: A ( a 1 n a 12 … a 1 n a 21 a 22 … a 2 n ⋮ a m 1 a m 2…...

重学SpringBoot3-安装Spring Boot CLI

更多SpringBoot3内容请关注我的专栏:《SpringBoot3》 期待您的点赞👍收藏⭐评论✍ 重学SpringBoot3-安装Spring Boot CLI 1. 什么是 Spring Boot CLI?2. Spring Boot CLI 的安装2.1. 通过 SDKMAN! 安装2.2. 通过 Homebrew 安装(适…...

代码复现(五):GCPANet

文章目录 net.py1.class Bottleneck:残差块2.class ResNet:特征提取3.class SRM:SR模块4.class FAM:FIA模块5.class CA:GCF模块6.class SA:HA模块7.class GCPANet:网络架构 train.pytest.py 论文…...

联邦学习实验复现—MNISIT IID实验 pytorch

联邦学习论文复现🚀 在精度的联邦学习的论文之后打算进一步开展写一个联邦学习的基础代码,用于开展之后的相关研究,首先就是复现一下论文中最基础也是最经典的MNIST IID(独立同分布划分) 数据集。然后由于这个联邦学习的论文是谷歌发的&#…...

2015年-2017年 计算机技术专业 程序设计题(算法题)实战_c语言程序设计数据结构程序设计分析

文章目录 20151.C语言算法设计部分2.数据结构算法设计部分 20161.C语言算法设计部分2.数据结构算法设计部分 2017年1. C语言算法设计部分2.数据结构算法设计部分 2015 1.C语言算法设计部分 int total(int n) {if(n1) return 1;return total(n-1)n1; } //主函数测试代码已省略…...

个人用计算理论导引笔记(待补充)

文章目录 一、正则语言预备知识确定性有穷自动机(DFA)设计DFA正则运算 非确定性有穷自动机(NFA,含有 ε \varepsilon ε,下一个状态可以有若干种选择(包括0种))正则表达式定义计算优…...

2024年诺贝尔物理学奖揭晓:AI背后的“造梦者”是谁?

想象一下,你早上醒来,智能音箱为你播放天气和新闻,中午你用手机刷视频,精准的推荐内容简直和你心有灵犀,晚上回家,自动驾驶汽车安全地把你送回家。这一切看似理所当然,背后却有一双无形的手推动…...

2024年AI 制作PPT新宠儿,3款神器集锦,让你的演示与众不同

咱们今儿聊聊最近超火的AI做PPT的工具。这年头,谁不想省事儿,少熬夜加班,多享受享受生活啊?所以,AI开始帮咱们搞定做PPT这种费时的活儿,我自然得好好研究研究。今天,我就给大家详细说说三款很火…...

CLion和Qt 联合开发环境配置教程(Windows和Linux版)

需要安装的工具CLion 和Qt CLion下载链接 :https://www.jetbrains.com.cn/clion/ 这个软件属于直接默认安装就行,很简单,不多做介绍了 Qt:https://mirrors.tuna.tsinghua.edu.cn/qt/official_releases/online_installers/ window 直接点exe Linux 先c…...

Qt记录使用QtAwesome

Qt记录使用QtAwesome 基本使用 基本使用 pro文件添加 CONFIG fontAwesomeFree include(QtAwesome/QtAwesome.pri) //实例化QtAwesome fa::QtAwesome* awesome new fa::QtAwesome(this); awesome->initFontAwesome();//设置外置适应 图标ICON的颜色color QVariantMap opt…...

ES6新增promise(异步编程新解决方案)如何封装ajax?

1.什么是异步? 异步是指从程序在运行过程中可以先执行其他操作。 2.什么是promise? Promise 是 ES6 引入的异步编程的新解决方案。语法上 Promise 是一个构造函数,用来封装异步 操作并可以获取其成功或失败的结果; 3.promise成功…...

Kubernetes--深入理解Service与CoreDNS

文章目录 Service功能Service 的常见使用场景 Service的模式iptablesIPVS Service类型ClusterIPNodePortLoadBalancerExternalName Service的工作机制EndpointEndpoint 与 Service 的关系Endpoint 的工作原理命令操作 CoreDNSCoreDNS 的配置CoreDNS 的典型插件Corefile 示例Cor…...

AI大模型:开启智能革命新纪元

1.AI大模型技术:智能革命的新引擎 自2022年11月30日OpenAI推出ChatGPT以来,这一大型语言模型(LLM)迅速走红,标志着AI领域进入了一个新的发展阶段,即AI大模型时代。 这一时代预示着AI正朝着通用人工智能&am…...

快速上手C语言【下】(非常详细!!!)

目录 1. 指针 1.1 指针是什么 1.2 指针类型 1.2.1 指针-整数 1.2.2 指针解引用 1.3 const修饰 1.4 字符指针 1.5 指针-指针 1.6 二级指针 2. 数组 2.1 定义和初始化 2.2 下标引用操作符[ ] 2.3 二维数组 2.4 终极测试 3. 函数 3.1 声明和定义 3.2 传值调用…...

红黑树的理解与实现(详解)

相关的数据结构: 搜索二叉树-CSDN博客 AVL树的创建与检测-CSDN博客 个人主页:敲上瘾-CSDN博客 个人专栏:游戏、数据结构、c语言基础、c学习、算法 目录 一、红黑树规则: 二、红黑树的插入 1.变色 2.单旋变色 3.双旋变色 三、…...

从一到无穷大 #37 Databricks Photon:打响 Spark Native Engine 第一枪

本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。 本作品 (李兆龙 博文, 由 李兆龙 创作),由 李兆龙 确认,转载请注明版权。 文章目录 引言技术决策JVM vs. Native ExecutionInterpreted Vectorization vs Code-GenRow vs…...

Java 字符串占位格式化

Java 提供了几种方式来处理字符串占位符,最常用的是 String 类的 format 方法和 MessageFormat 类。以下是这两种方法的详细说明和示例。 1、String.format 基本语法: String formatted String.format("格式字符串", 参数1, 参数2, ...); …...

基于netty实现简易版rpc服务-理论分析

1.技术要点 1.1 rpc协议 定义一个rpc协议类,用于rpc服务端和客户端数据交互。 1.2 netty粘包半包处理 由于数据传说使用tcp协议,rpc协议的数据在网络传输过程中会产生三种情况: 1)刚好是完整的一条rpc协议数据 2)不…...

Elasticsearch高级搜索技术-全文搜索

目录 倒排索引 (Inverted Index) 示例 分词器 (Analyzer) 评分机制 (Scoring) 查询执行 match 查询 match_phrase 查询 全文搜索是Elasticsearch的核心功能之一,它通过复杂的算法和数据结构来提供高效的搜索能力。为了深入理解其工作原理,我们需要…...

案例分享—国外优秀UI卡片设计作品赏析

国外UI设计注重用户体验,倾向于采用简洁的布局、清晰的排版和直观的交互方式,减少用户的认知负担。卡片式设计能够完美利用屏幕空间,使内容一目了然,易于用户快速浏览和阅读,从而提升了整体的用户体验。 更加注重扁平化…...

Go语言基础学习(Go安装配置、基础语法)

一、简介及安装教程 1、为什么学习Go? 简单好记的关键词和语法;更高的效率;生态强大;语法检查严格,安全性高;严格的依赖管理, go mod 命令;强大的编译检查、严格的编码规范和完整的…...

STM32—FLASH闪存

1.FLASH简介 STM32F1系列的FLASH包含程序存储器、系统存储器和选项字节三个部分,通过闪存存储器接口(外设)可以对程序存储器和选项字节进行擦除和编程 我们怎么操作这些存储器呢?这就需要用到这个闪存存储器接口了,闪…...

AP上线的那些事儿(1)capwap建立过程、设备初始化以及二层上线

1、了解FITAP与AC的建立过程 之前我们已经知道了FATAP与FIT是一对双胞胎一样的兄弟,FAT哥哥能够直接独立使用当AP桥接、路由器等,而弟弟FIT则比较薄弱,独自发挥不出功效,需要一位师傅(AC)来带领&#xff0c…...

10 django管理系统 - 管理员管理 - 新建管理员(通过模态框和ajax实现)

在文章“04 django管理系统 - 部门管理 - 新增部门”中&#xff0c;我们通过传统的新增页面来实现部门的添加。 在本文中&#xff0c;我们通过模态框和ajax来实现管理员的新增。 首先在admin_list.html中新建入口&#xff0c;使用按钮 <div class"panel-heading&quo…...

Mysql中表字段VARCHAR(N)类型及长度的解释

本文将针对MySQL 中 varchar (N)类型字段的存储方式进行解释&#xff0c;主要是对字符和字节的关系的理解。 1. varchar (N) 中的 N varchar (N) 中的 N 表示字符数&#xff0c;而不是字节数。这意味着 N 表示你可以存储多少个字符。 字符数&#xff1a;指的是字符的个数&…...