news 2026/10/16 3:34:19

进程与线程:从浏览器架构看懂页面卡顿与性能优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
进程与线程:从浏览器架构看懂页面卡顿与性能优化

说实话,干前端或者平时用电脑稍微有点好奇的人,肯定都碰到过这样一个画面:标签页开了一堆,其中一个页面卡成了“未响应”,你正准备摔鼠标,结果发现其他标签页还能正常滚动、点按钮,甚至还能开个新标签出来压压惊。这时候你嘴里多半会蹦出一句:这浏览器不是挂了吗?怎么其他页面没事?

答案就藏在今天要聊的两个词里:进程(Process)和线程(Thread)。这两个概念不仅是操作系统的地基,也是现代浏览器的骨架。我把它们彻底搞清楚之后,再回头看真机上那些奇奇怪怪的卡顿、白屏、内存暴涨,基本都能猜个八九不离十。

这篇博文打算把这个话题讲透,把进程和线程掰开揉碎,从“它们是啥”“为什么浏览器要搞一堆进程”“渲染进程内部怎么个运转法”一直聊到“JS单线程到底是怎么做到不卡死”以及“搞懂之后对实际性能优化有什么用”。新手能从中建立完整的概念地图,老手也能当一次框架级复习。

1. 先把这两个概念拧清楚:进程与线程到底是什么

1.1 一个生活类比:厨房与厨师

想理解进程和线程的区别,最朴素的办法是拿厨房打比方。

进程就是一整套独立的厨房。这个厨房里有自己的灶台、自己的锅碗瓢盆、自己的食材储备、自己的燃气管道——对应到计算机里,就是独立的内存空间、文件句柄、执行上下文。两个进程就像两间完全隔离的厨房,各有各的门锁,互不串门。你在这个厨房里炒菜,隔壁厨房把锅烧穿了,你也闻不到味、伤不着一根汗毛。

线程则是厨房里真正干活的人。一个进程至少有一个线程,也可以有好多个。一个灶台做饭做到一半,另一个人可以同时切菜、洗菜、摆盘——这些人共享同一间厨房,共享灶台、食材和锅碗瓢盆。换句话说,同一个进程内的多个线程,共享这块内存区域和资源,协作很方便,但也意味着:一个线程捅了篓子,同厨房的其他人都可能被牵连。

所以一句话总结:进程是操作系统分配资源的基本单位,线程是CPU调度执行的基本单位。进程负责隔离,线程负责干活。进程是“地盘”,线程是“在这个地盘上干活的人”。

1.2 进程里的内存布局:为什么进程是“隔离小天地”

一个进程在内存里长什么样?现代操作系统给每个进程分配了一块独立的虚拟地址空间。从高地址到低地址,大体上分为栈区、堆区、数据段和代码段。栈区自动管理,存放局部变量和函数调用信息;堆区手动管理,存放程序动态申请的内存;代码段放机器指令;数据段放全局变量和静态变量。

因为各进程的虚拟地址空间互相独立,一个进程里发生的非法内存访问、栈溢出、野指针乱写,基本不可能直接影响另一个进程。这种隔离是操作系统稳定性的第一道防线。

但线程就不一样了。同一进程内的所有线程共享堆区、数据段和代码段,只是各自拥有独立的栈和寄存器上下文。这意味着线程A往一个共享数组里写数据,线程B马上能读到。好处是效率高、通信方便,坏处是一旦多个线程同时改同一个数据,就出竞争条件了。这也是后面聊到浏览器里一些内存访问策略时,要反复提的底层逻辑。

提示:每次新开一个进程,操作系统都要创建一整套页表、文件描述符、内存映射关系,成本比开线程高得多。这也是设计浏览器架构时需要在“稳定隔离”和“资源消耗”之间做取舍的根本原因。

2. 浏览器为什么要搞出一堆进程:从架构演进说起

2.1 早期单进程时代的噩梦:一崩全崩

今天说起多进程架构,大家觉得理所当然,但浏览器不是一开始就这么设计的。早期的浏览器采用单进程架构,整个浏览器的“首都”有机物全放在一个进程里:页面渲染、JS执行、网络请求、插件运行、图片解码,全挤在一块儿。

单进程最要命的问题有三个。

第一,稳定性极差。某个标签页上的Flash插件崩了,整个浏览器立刻全部白屏。某个网页有无限循环的JS,整个浏览器的界面直接卡死。你只有“结束进程”一条路,所有开着的页面全没。

第二,安全性很难做。所有页面、插件、脚本都共享同一个地址空间,一个恶意网页理论上可以读取或篡改浏览器里其他页面的数据。那时候的浏览器沙箱能力非常弱。

第三,性能无法分摊。一个网页的崩溃无法被单独清理,一个网页占用的资源也无法被单独回收,长时间使用后,整个浏览器会越来越卡、内存越来越大。

所以后来主流的现代浏览器选择走向多进程,本质上牺牲一部分内存空间换取稳定性、安全性和流畅度。一句话:用内存换稳定,用隔离换安全。

2.2 现役浏览器的多进程架构长什么样

以主流Chromium内核家族为例,打开任务管理器你会看到一堆进程,它们大致分成这么几个角色:

进程角色主要职责特点
浏览器主进程管理窗口、地址栏、书签、各标签页的创建销毁,以及全局UI绘制唯一的,挂了整个浏览器就没了
GPU进程负责图形加速、合成图像、把页面内容最终输出到屏幕全局一个,负责和显卡驱动打交道
网络进程负责网络资源加载、缓存管理、各种网络协议处理全局一个,独立出来是为了安全性和故障隔离
渲染进程负责HTML解析、CSS样式计算、布局、绘制、JS执行每个标签页一个,或每个站点一个
插件进程/扩展进程负责运行浏览器扩展、插件(如PDF阅读器等)按需创建,独立沙箱
工具进程(Utility)处理索引数据库、文件系统访问等杂项任务按功能临时创建

这里有个细节值得注意。现代浏览器并不一定真的“每个标签页一个进程”,因为有**站点隔离(Site Isolation)**机制。简单说,如果两个标签页属于同一个站点(同协议、同域名或同站点),浏览器可能把它们放到同一个渲染进程里,以便共享一些数据和缓存;如果涉及跨站iframe,浏览器甚至会为同一个页面里的不同站点再单独拆一个渲染进程,保证相互之间不能随便窥探。

从用户角度看是“这个标签页卡住了,其他没事”,背后真正的原因是:这个标签页对应的渲染进程崩溃了,浏览器主进程检测到后,把它的整个界面变成“崩溃页”,而其他标签页是独立进程,自然不受影响。

2.3 各进程之间怎么说话:IPC信道

进程之间是隔离的,但是一个浏览器总得让标签页和主窗口保持同步。地址栏要能显示当前页面标题,页面里的下载进度要告诉主窗口,GPU进程要把渲染好的图像送回屏幕……这些跨进程的事怎么干?

答案叫进程间通信(IPC,Inter-Process Communication)。浏览器内部使用了一套基于消息传递的IPC机制,进程A把数据序列化,塞进一条消息,通过操作系统提供的IPC通道(比如管道、socketpair、共享内存加信号量)发给进程B;进程B反序列化拿到数据,再执行相应逻辑。

这套机制要快,又不能阻塞。所以Chromium在设计时大量使用异步消息投递,接收方在专门的IO线程上收消息,然后投递到对应业务线程的任务队列里。这也是为什么后面渲染进程里会有专门的IO线程这个角色。

注意:IPC是有成本的对,跨一次进程好比把一袋米从A楼扛到B楼,比同一栋楼里从1层搬到2层贵多了。所以浏览器内部对高频通信做了优化,比如通过共享内存传输大的图像帧,避免反复复制数据。

3. 渲染进程内部:一个页面到底是怎么跑起来的

3.1 五大线程的分工与协作

一个渲染进程,表面上只是“打开了某个网页”,内部却是一个微型操作系统。它至少包含下面这些核心线程。

主线程(Main Thread):页面生命周期的总指挥。主要负责HTML解析、CSS样式计算、布局、绘制命令生成、JS执行、处理用户输入事件。可以说90%的前端工作都发生在这个线程上。

合成线程(Compositor Thread):专门负责把页面各图层合成到一起,并处理滚动、缩放和动画的合成。它能独立于主线程响应一些滚动操作——这就是为什么有时候JS卡死了,页面还是能上下滚的答案所在。

IO线程(IO Thread):负责接收所有来自浏览器主进程和其他进程的IPC消息。网络请求的结果、用户输入事件、浏览器的生命周期指令,都先到IO线程,被解析后投递到主线程的任务队列中。

Worker线程(Web Worker/Service Worker等):可以动态创建和销毁,用于在后台执行JS脚本,不阻塞主线程。专门的图形加速线程和光栅化线程通常也归在这一类。

存储/数据库线程:负责处理IndexedDB、CacheStorage和本地文件等异步IO任务。

这就像一条完整的产品生产线,主线程干重活,合成线程干精活,IO线程做前台接待,Worker线程做外派临时工,所有线程都围绕着“把网页流畅地送到用户眼前”这一目标协作。

3.2 主线程的一天:解析、样式、布局、绘制、合成

拿用户在地址栏输入一个网址并按下回车开始,页面抵达后,主线程的工作流程基本是固定的。

第一步,解析HTML并构建DOM树。浏览器一边下载HTML字节流,一边解析成Token,再构建成节点对象,最终形成DOM树。这个阶段脚本标签的出现会阻断解析——遇到同步script标签,解析器会停下来,先下载并执行脚本,然后再继续。这就是为什么工程上都推荐把script放在body底部或者加defer。

第二步,计算CSS样式。拿到CSS规则后,浏览器会为每个DOM节点匹配选择性样式,计算出每个节点的最终样式。这一步的复杂度跟选择器的复杂度和DOM节点数成正比。通配符选择器和深层后代选择器都是性能杀手,原因就在这。

第三步,布局(Layout)。有了DOM树和样式后,主线程为每个节点计算几何位置,输出一棵布局树。布局树的每个节点记录了坐标、尺寸、层叠关系。如果有“绝对定位”“浮动”等属性,计算量会明显加大。

第四步,绘制(Paint)。布局完并不意味着屏幕上有东西。主线程还要把每个可见节点生成对应的绘制指令列表,再把这些指令交给合成线程。绘制指令不实际画像素,只是类似“在这里画个红色矩形”“这里贴这张图”这样的命令。

第五步,合成与显示。合成线程接收所有图层的绘制指令,把页面拆分成若干图层(Layer),分块(Tile)交给光栅线程去真正把像素算出来,再拼合(Composite)成最终图像帧,交给GPU进程输出到显示器。

这套流程每一帧都可能完整走一遍,所以一旦其中某个环节耗时太猛,用户的直观感受就是卡顿、掉帧。

3.3 线程之间的通信:postMessage与任务队列

前面说线程共享进程内的内存区域,那渲染进程里主线程和Worker线程是如何协作的?

答案是通过消息事件。主线程创建了一个Worker线程之后,双方通过postMessage互相发消息。消息的本质是:发消息时,数据会被结构化克隆(structured clone)拷贝一遍,然后在接收方的事件循环里生成一个MessageEvent,排队等待对方线程处理。

这里有个关键的架构设计:同进程内线程之间的通信,不是直接互相打断,而是通过任务队列异步投递。

每个线程都有自己的任务队列。发消息的一端只是把任务塞进对方的队列,接收端线程忙完手头的事之后,从任务队列里取出下一条继续处理。这样设计的好处是线程之间不会随便抢占执行权,数据的访问边界清晰很多,出bug的概率也小。

实操经验:跨线程通信请尽量避免把超大对象传过去,结构化克隆本身就耗时,量大会造成明显的延迟。如果真要传大数据,考虑Transferable对象(比如ArrayBuffer转交所有权),用“移交”代替“拷贝”。

4. 别被“单线程”骗了:JS的Event Loop到底在转什么

4.1 为什么JS必须是单线程:DOM只允许一个老板

刚聊完渲染进程里有一堆线程,转头又告诉你JS是单线程,这不是自相矛盾吗?

不矛盾。JS的单线程指的是“每一个JavaScript执行上下文同时只有一个线程在执行代码”。渲染进程里的主线程虽然跑JS,但也跑解析、样式计算、布局和绘制;Worker线程虽然也跑JS,但它没有DOM访问权。关键在于:操作系统级别,同一个时间点,每一条JS执行流都是单线程在跑,不存在两个线程同时执行同一段共享状态的JS代码。

原因其实很简单:DOM不是线程安全的。如果两个线程同时修改同一个DOM节点,一个改样式,一个删节点,浏览器根本没法保证页面状态是一致的。为了避免开发者每天处理数据竞争、死锁、锁风暴,设计者直接选择了单线程执行JS这条路,让所有对DOM的访问都串行化。

就好比一家奶茶店只有老板一个人能做招牌奶茶,其他人不能插手。虽然店里可能有员工负责打包、清洁、接外卖,但核心制作环节永远只有老板一个人在操作。

4.2 宏任务、微任务与nextTick的微妙顺序

虽然JS是单线程的,但浏览器不可能只有一个任务要做。于是就有了**事件循环(Event Loop)**这个机制来排队处理所有任务。

事件循环的基本套路是这样的:

  1. 从宏任务队列里取出一个队首任务(宏任务包括script整体代码、setTimeout回调、setInterval回调、I/O事件回调、postMessage消息等)。
  2. 执行这个宏任务,直到调用栈清空。
  3. 执行完一个宏任务后,立即把当前微任务队列里的所有任务全部执行完(微任务包括Promise回调、MutationObserver、queueMicrotask等)。
  4. 执行完所有微任务后,可能触发一次渲染更新(浏览器根据帧率决定)。
  5. 在渲染过程中,requestAnimationFrame回调会在这阶段执行。
  6. 回到第1步,继续取下一个宏任务。

这里最容易被忽视的是微任务优先级远高于新的宏任务。比如你在一个Promise回调里再嵌套一个Promise,即使外层微任务队列排了很多微任务,也会一口气全部执行完,而不是中间插进去执行setTimeout。

举个例子:

setTimeout(() => { console.log('宏任务1'); }, 0); Promise.resolve().then(() => { console.log('微任务1'); }).then(() => { console.log('微任务2'); }); console.log('同步代码');

输出顺序是:同步代码、微任务1、微任务2、宏任务1。

原因就是事件循环在拿到第一个宏任务(整体script)并执行完之后,会先清空微任务队列,所有微任务执行完才会去宏任务队列取下一个setTimeout。

这套机制对前端的影响很实际:如果你在业务代码里写了大量的Promise链,它可能在一次渲染周期之前全部执行完,阻塞主线程,拉长“渲染前没活干”的空窗期。反之,如果需要把一段低优先级逻辑往后推、且不阻塞渲染,考虑requestIdleCallback(如果支持的话),或者用setTimeout降级,把任务丢回宏任务队列尾部。

4.3 Web Worker:受限的多线程逃生门

前面一直说“DOM不是线程安全的”,那如果我就是想多开几条线程做点计算密集型任务怎么办?

浏览器给了答案:Web Worker。Worker线程能跑完整的JS引擎,能做大量纯计算、数据处理、网络请求,但它不能操作DOM,不能读写window对象的大部(看不到窗口,也没法弹alert),更不能直接访问本地文件系统。

Web Worker常见的使用场景很典型:

  • 大数据量列表的过滤、排序、分组计算。
  • 图片或音视频的像素级处理、编解码。
  • 本地数据库(IndexedDB)的批量读写操作。
  • 长轮询、WebSocket消息预处理。
  • 加密、哈希计算等CPU密集任务。

实际操作中,主线程把原始数据通过postMessage传给Worker,Worker算完后把结果传回来。注意把大块数据切分成小份来分批次传,以免单次消息阻塞主线程过久。

此外还有两个变种:SharedWorker可以被多个窗口共享,适合做跨页面的数据同步;Service Worker负责拦截网络请求和做缓存策略,是实现PWA离线能力的核心。三者虽然都叫“Worker”,但定位完全不同,面试聊起来值得分清楚。

5. 理解了进程线程之后,前端性能优化能整哪些活

5.1 长任务与帧预算:别让主线程加班

搞懂了渲染进程的主线程要扛这么多活,性能优化的思路就变得非常清晰了:主线程每一次任务处理,都是在跟渲染抢时间。

屏幕刷新率一般是60Hz,也就是一帧16.67毫秒。在这个时间窗口里,主线程要完成输入事件处理、JS执行、样式计算、布局、绘制指令提交。任何一段JS执行超过这个预算,帧就得往后拖,表现为掉帧、卡顿。

用实时查看长任务的工具,观察Performance面板里的“Task”记录。如果某个Task超过了50毫秒(Long Task阈值),基本可以判定为需要优化的对象。

典型的优化手段包括:

  • 把大段同步计算拆散,用requestIdleCallback分片处理。
  • 把纯计算任务塞进Web Worker,让主线程只负责展示。
  • 减少DOM访问次数,尤其是批量读取和写入交错进行,会强制浏览器反复重排。
  • 避免强制同步布局。比如循环里先读offsetWidth再改style.width,每次循环都触发重排,性能极差。批量读、批量写,或者用display:none先离线操作再恢复。
  • 用CSS动画替代JS驱动的动画,把变换交给合成线程去处理(transform和opacity动画不会触发布局)。

5.2 减少进程间的无谓通信

聊到进程了,还得说说跨进程通信的成本问题。

前端可能没意识到的场景是:比如一个页面里嵌了跨站iframe,如果这个iframe频繁呼起alert、或者主页面通过postMessage跟iframe大频率通信,这些都是跨进程消息,比同进程内的线程通信更贵。

再比如drag事件、scroll事件触发的跨进程消息,频率极高。滚动时每帧都可能有一堆输入消息从浏览器主进程发到渲染进程的IO线程,然后投递给主线程。如果同时主线程还在跑长任务,就会产生输入延迟。所以实际开发里,监听scroll/resize时务必加节流,把消息频率降下来。

另一个容易忽略的点是Tab切回时CPU暴增。浏览器为了省资源,会在后台时限制定时器精度和频率,但如果你用WebSocket或频繁轮询,后台标签页依然可能在持续拉取数据、触发渲染更新。这种情况下,考虑用document.visibilitychange事件主动暂停后台任务,是实打实的优化。

5.3 实测技巧:浏览器任务管理器看什么

想亲眼看到前面讲的这套架构,有个很直观的东西:浏览器自带的“任务管理器”。

在Chrome里按Shift+Esc就能调出。打开后你会看到每一个进程的名字、内存占用、CPU占用、网络占用。这时候配合开多个不同站点的标签页,就能很清晰地看到每个渲染进程被单独列出来。

个人比较推荐的做法是:开一个性能试验项目,一个标签页空页面,一个标签页跑复杂动画,一个标签页开一堆定时器,然后盯住任务管理器观察哪类进程在飙升。这种观察方式会让“进程隔离”“渲染进程”的概念一下子落地,比看十篇架构文章都顶用。

如果发现某个迟迟不关的页面占用了大量内存,直接在那个进程上点“结束进程”,其他标签页完全不受影响——这就是最直观的多进程稳定性实验。

6. 把概念用在真机调试里:两个实战视角

6.1 卡顿排查思路:从进程线程角度一步步定位

平时帮人排查网页卡顿,我的流程基本是固定的。

打开DevTools的Performance面板,录制一段操作,重点看主线程上有没有超长Task。如果有,展开那个Task,看具体的调用栈,是执行了某个耗时的JS函数,还是触发了巨大的样式布局。

接着切到Memory面板,做一次堆快照对比,如果内存曲线持续上升且GC后不回落,基本就可以判断是内存泄漏。结合这张图理解:主线程不仅要执行JS,还要响应每一帧的渲染指令,一旦GC时间变长,主线程执行JS的空窗期就会被切断,帧率自然就下来了。

如果Performance面板看不出明显长任务,但页面依旧卡顿,就得怀疑合成线程或者GPU进程了。这时候点开DevTools里的Rendering面板,开启“Layer Borders”和“FPS meter”看一下是否出现了过多图层、或者某些区域不断重绘。合成线程处理的图层过多、图层碎片过多,也会吃掉大量性能,即便主线程看起来很轻松。

6.2 一个真实的排查故事:难以定位的“幽灵”卡顿

我曾经遇到过一个很典型的案例。某个某公司内部管理系统,打开之后滚动流畅,但每隔大约三四十秒,页面会卡一下,时间很短,大概几百毫秒。

一开始怀疑JS里有重型定时任务,可Performance录制了五分钟也几乎没看到长任务。后来开着浏览器任务管理器盯着看,发现这个页面所在的渲染进程CPU每隔一段时间就跳一下尖峰,但主线程的Task记录里干干净净。

最后发现,罪魁祸首是某图表组件里负责监听鼠标移动的代码,在鼠标滑出图表区域后没有解绑,导致鼠标只要停在页面上,后台就会高频触发布局计算。由于触发频率高但单次计算量小,Performance面板的Task时间被摊薄了,不仔细看很难发现问题。

这个问题用进程跟线程的视角很容易解释:事件消息不断从IO线程投递到主线程,虽然每个任务短小,但累积起来挤占了主线程的帧预算。所以排查卡顿不能只看单次长任务,还得看任务队列里是否有高频率的“小蚊子任务”。

桌面端和移动端的表现也有区别。桌面端CPU多核且性能强,偶尔几个小任务不会造成明显掉帧;手机端主频低、核心调度有限,同一个小任务可能就足够让画面掉一帧。这也是为什么很多“电脑上没问题,手机上卡成PPT”的问题,本质出在高频小任务上。

7. 最后的实操心得

把这套进程线程的东西彻底弄明白之后,回头看浏览器,它就不再是“一个软件”了,而是一个由多个小世界组成的系统。每个页面都在自己的小隔间里独立生活,主线程是那个小隔间里最忙的管事人,合成线程在旁边帮忙干精细活,Worker线程是随时听候调遣的外援。

我个人实际操作中的体会是:理解这些东西的性价比极高。前端性能优化很多方案看似是个“最佳实践”,但背后真正的原因都指向进程和线程的协作机制。明白了transform为什么比left动画流畅,明白了setTimeout为什么不靠谱,明白了为什么长列表分片渲染远比一次性渲染要好,这些知识就会内化成一种直觉,而不是背下来的规则。

最后再分享一个小技巧:没事可以专门开一个空白标签页,按Shift+Esc打开浏览器任务管理器,看着那一排进程名字发呆五分钟。多看几次,你就能直观感知到每个进程的边界、每个标签页的重量。下次再遇到浏览器卡顿、白屏、内存爆炸,你手里的排查方向会比以前清晰非常多。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/16 3:34:04

Windows IIS 发布 ASP.NET 网站完整指南:从环境配置到常见错误排查

很多开发者在本地用 Visual Studio 跑 ASP.NET 项目风生水起,一部署到服务器就各种幺蛾子。这事我经手过不少,从最初的摸索到后来闭着眼都能配完,说到底就是几个关键点没打通:发布方式选对没有、IIS 功能装全没有、应用程序池和权…

作者头像 李华
网站建设 2026/10/16 3:32:55

海姆休息室 | AI Agent 多角色互动终端 | 自制软件技术分享

作者:青尘工作室 CyanDust_青尘 | 保留所有权利,允许规范转载。 最近,我们在 GitHub 上开源了《海姆休息室》APP,这是一款基于《尘白禁区》世界观设定的多角色 AI Agent 互动终端,基于 JS 纯前端框架开发,…

作者头像 李华
网站建设 2026/10/16 3:32:24

Linux下海康监控视频QT demo源码解析与实战避坑指南

简介:这份资源是面向Linux平台监控视频开发者的Qt示例工程源码,适合具备C基础、希望将海康摄像头接入自研客户端或做系统集成的技术人员。源码围绕网络通信、多媒体播放、视频解码、设备发现与配置、多线程处理及错误日志等环节展开,可帮助读…

作者头像 李华
网站建设 2026/10/16 3:32:24

实验室管理系统毕设工程包:源码论文SQL文档一站式跑通

简介:这份资源是面向计算机相关专业毕业设计学生与Java项目实战学习者的实验室管理系统完整资料包,基于SpringBoot框架与MySQL数据库开发,开发工具为IntelliJ IDEA,可直接作为毕设、课程设计或期末大作业使用。压缩包约80.62MB&am…

作者头像 李华
网站建设 2026/10/16 3:31:23

深入理解listen函数的backlog参数:内核队列机制与高并发调优

1. 从“监听”这个词说起如果你写过几个网络程序,一定对这段代码不陌生:int listen_fd socket(AF_INET, SOCK_STREAM, 0); bind(listen_fd, ...); listen(listen_fd, 128); accept(listen_fd, ...);socket创建套接字,bind绑定端口&#xff0…

作者头像 李华
网站建设 2026/10/16 3:31:22

OpenHarmony下基于React Native的TabBar实现与性能优化

1. 项目概述与整体设计思路1.1 为什么要在OpenHarmony上使用RN来写TabBar先交代一下背景。我最近在做一个基于React Native for OpenHarmony(后面简称RNOH)的跨平台应用项目,需求里明确要求应用的主框架必须包含底部TabBar导航——这也是几乎…

作者头像 李华