首页 / 文章

为什么React赢得了前端领域,而后端仍保持多语言并存的局面。

为什么大型企业会将React与Java、Go和Python服务搭配使用,同时保留Node.js用于BFF层,并为初级开发者提供下一步学习建议。

发布者:REACTAPP.TOP阅读约 6 分钟1477 词

来源: Why Your Favorite Apps Use React on the Frontend, but Not Node.js on the Backend

React 在前端领域占据了绝对优势。后端领域从未出现能与之抗衡的强大技术,那些从 MERN 技术栈课程转向拥有真实流量规模公司的开发者往往很快就能察觉到这一点。

培训课程常常将 Mongo、Express、React 和 Node 宣传为一套完整的解决方案:一种语言即可构建整个技术栈,从而实现全栈应用的开发。侧项目以及小型 CRUD 应用似乎也印证了这一观点。然而,当在拥有数百万用户的公司获得第一份工作时,情况就完全不同了。UI 仍是 React,这在意料之中;核心服务则使用 Java,高吞吐量的微服务由 Go 开发,机器学习流程则依赖 Python。Node.js 主要出现在为前端聚合 API 的薄层中。在大规模应用场景下,它更像是为强大的后端提供支持的辅助工具,其存在原因也颇为具体。

原因一:单线程,多任务处理

Node.js在单线程上运行JavaScript。它处理I/O操作非常高效,但一次只能执行一项需要大量CPU算力的任务。可以想象一家只有一名速度极快的服务员的餐厅:接收订单(相当于处理数据库和网络请求)对它来说毫不费力。但如果有顾客点了一份需要30分钟才能准备好的五道菜大餐(相当于CPU密集型任务),这名服务员就会忙得不可开交,导致其他顾客都得等待。

一个视频平台展示了这在实际应用中的表现。当用户上传一个4K分辨率的文件时,服务器必须:

  1. 接收该文件。
  2. 将其转码为多种分辨率,如1080p、720p和480p。
  3. 生成缩略图。
  4. 提取元数据。
  5. 将处理后的结果存储到相应位置。

在 Node 进程中执行所有这些操作会阻塞其事件循环。其他上传任务会等待,其他 API 调用会排队,应用程序也会停止响应。Java 和 Go 使用多线程,因此可以有一线程处理视频,同时其他线程负责处理 API 请求和身份验证。Node 非常适合处理那些依赖 I/O 的任务,比如 API、实时聊天和数据流。而依赖 CPU 的任务则是它的弱点,大型应用程序中这类任务非常多。

第二个原因:微服务让每个团队能够自主选择

大型企业大多已停止构建单体应用。单体应用将身份验证、支付、通知和推荐功能整合在同一个代码库中。而微服务架构则将这些功能拆分成独立的服 务,通过网络相互通信。

这种分离让每个团队都能自由选择编程语言。处理支付业务的团队可以选择Java,因为它在金融交易领域已有成熟应用。负责实时聊天的团队可以选择Go,因为它能支持数千个并发连接。而负责推荐系统的团队则可以选择Python,得益于其强大的机器学习库。Node最终只是众多选项之一,很少成为默认选择。

为何Go和Java占据主导地位

Go源自谷歌,旨在解决早期编程语言的痛点。它的优势包括:

  • 并发处理能力。Goroutines能在极少的内存占用下维持大量同时进行的连接。
  • 启动速度。程序编译为原生机器码,几乎可以瞬间启动。
  • 部署便捷。只需一个不依赖运行时环境的二进制文件即可完成部署。

Uber在其最繁忙的服务中依赖它,Twitch则使用它实现实时聊天,而Dropbox在将部分代码从Python迁移后也报告了显著的性能提升。

25多年来,Java一直是企业界的默认选择。虽然它已过时,但却非常可靠:

  • 它在银行、航空业以及大型电子商务领域已被广泛验证。
  • 其生态系统包括Spring Boot、Hibernate以及数千个开源库。
  • 静态类型能在编译阶段就发现许多错误,从而避免问题出现在生产环境中。
  • 用于性能分析、监控和调试的工具也经过数十年的不断优化。

Netflix、Amazon和Airbnb都使用它来运行核心的后端系统。这些企业需要在大规模环境中保持稳定性,因此并不追求潮流。

第三个原因:历史积淀与惯性

大型企业拥有悠久的历史。亚马逊成立于1994年,Netflix成立于1997年,谷歌则成立于1998年。它们拥有数百万行的Java、C++和Python代码,经过数十年构建的基础设施,以及精通这些编程语言的工程师。仅仅因为某种技术时髦就改用Node来重写代码是绝不可能的。大型企业的首席技术官不会因为某种语言在开发者中流行,就将其用于支撑直接创造收入的支付系统。

为何React是个例外

这些企业选择React是因为它解决了实际问题。在此之前,构建复杂的用户界面极为困难:复杂的jQuery代码、令人困惑的Backbone模式,还有Angular 1.x的消化循环问题。React带来了组件架构、提升性能的虚拟DOM、声明式用户界面,以及包括Next.js和React Native在内的庞大生态系统。它之所以能胜出,是因为它比其他替代方案更优秀。

Node在服务器端从未有过同样不可或缺的地位。它在特定场景下表现良好,是不错的选择,但对于大多数重要的后端工作而言,它并不明显优于Java、Go或Python,因此并非首选。

大型应用程序的架构设计

典型的架构图显示,React前端会调用API网关,而网关则将每个请求转发到相应的后端服务。在其背后:

  • Node.js前端后端负责处理前端特有的逻辑、API聚合以及实时事件处理,这也是Node的强项所在。
  • Java核心服务负责处理支付、订单、用户认证和库存管理等关键功能,这些部分绝不能出错。
  • Go服务则承担实时聊天、流媒体处理以及需要高并发的场景。
  • Python服务则用于实现推荐系统、图像处理和分析功能。

每个服务都拥有自己的数据库,这些服务通过 gRPC、WebSockets 或 Kafka 等消息队列进行通信。前端领域有明显的最佳选择,而后端则采用多种编程语言,根据具体需求选择合适的工具。

各编程语言的简要对比

  • Node.js 适合初创公司、最小可行产品以及 BFF 层开发。其开发速度较快,npm 生态系统极为庞大,而且 JavaScript 开发者遍布各地。不过它不太适合视频处理或金融交易类应用。
  • Java 是值得信赖的通用语言。虽然学习曲线较陡且启动速度较慢,但当在黑色星期五凌晨 3 点出现故障是不可接受的场景时,Java 是最佳选择。
  • Go 就像是如今重新设计的后端语言:快速、简洁且具备并发处理能力。它的缺点是生态系统相比 Java 还不够成熟。
  • Python 在数据科学和机器学习领域占据主导地位。不过对于高并发 API 来说,全局解释器锁确实是一个严重的瓶颈。
  • C++ 适用于那些对速度要求极高的场景,比如游戏引擎、嵌入式系统以及高频交易系统,它并不适合用于 Web API。
  • 这对初级开发者意味着什么

    这些并不代表 Node 不好。对于那些注重快速上市时间的初创公司和最小可行产品而言,它依然是一个极佳的选择;同时它也适用于前端后的服务层、聊天和实时更新等实时功能、AWS Lambda 或 Vercel Edge 上的无服务器函数,以及用于在投入更复杂的开发环境之前测试想法的原型。

    任何想要在大型企业中发展的人都不应仅依赖MERN技术栈。更实用的习惯是了解系统的运作原理,从而为每项工作选择合适的工具。而错误的观念则是认为掌握了JavaScript就意味着什么都能做。

    最优秀的开发者不会固守某一种语言。他们可能会用JavaScript编写界面代码,在审查业务逻辑时使用Java,理解团队为何选择Go来开发微服务,同时也能判断何时该使用Python。他们是多语言专家,这是因为他们明白不同问题需要不同的解决方案,而非为了炫耀。

    每项工作都有合适的工具

    React在界面层占据了优势,各大公司使用它自有其理由。后端更适合作为一个生态系统来理解,而非一场竞争。Java、Go、Python、C++、Rust和Node都有各自的适用场景,开发日常应用的公司并不会强制要求所有功能都用同一种语言实现。

    开发者的目标是为问题找到解决方案,而非仅仅使用自己熟悉的语言,这有时意味着需要学习新技能。持有MERN证书的初级开发者不必惊慌,Node是一个不错的起点。在此基础上继续深入:研究一下Java Spring Boot项目,编写一个简单的Go微服务,弄清楚为什么公司的支付系统要用Java而非JavaScript实现。最优秀的工程师并非那些掌握最多语言的人,而是那些明白每种语言的存在原因以及适用场景的人。

    相关阅读

  • Node.js服务器究竟能处理多少请求? —— 对Heroku和AWS上Express API的负载测试结果与Django的对比、40K次/秒的处理能力估算,以及导致真实API性能下降的因素。