前端科学计算:从原理到边界

一份关于”纯 HTML 文件能否做科学计算”的完整知识梳理。 来源:与 AI 的对话记录,整理为系统化文档。


一、核心结论

纯网页前端完全可以做科学计算。 一个 HTML 文件 + 浏览器,不安装任何软件、不配置任何环境,就能实现表达式求值、矩阵运算、方程求解、微积分、函数绘图、统计分析等功能。将文件夹复制到任意电脑,浏览器打开即可复现。

唯一需要的是引入一个第三方库 math.js 来提供数学能力,获取方式有两种(见下文)。


二、JavaScript 包的加载机制:CDN

2.1 与 Python 的本质区别

Python 的包管理是”下载到本地安装”,JavaScript 在浏览器环境中是”每次从网上取”。

Python 模式——把书买回家:
  pip install mathjs
  → 包下载到你电脑硬盘的 site-packages/ 目录
  → 以后每次运行从硬盘读取
  → 断网也能用

JavaScript(浏览器)模式——每次去图书馆借:
  <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/12.4.0/math.min.js"></script>
  → 浏览器打开网页时,向这个网址发起请求,把代码下载到内存
  → 代码在当前网页的内存中"活"着
  → 关掉网页,内存释放,什么痕迹都不留
  → 断网则无法加载

2.2 CDN 是什么

CDN(Content Delivery Network,内容分发网络)本质上是全球分布的”代码图书馆”

常见的 CDN 服务:

  • cdnjs.cloudflare.com
  • unpkg.com
  • jsdelivr.net

别人把 math.js 上传到这些平台,全世界任何人都可以通过网址引用。浏览器读到 <script src="网址"> 时,会自动发起 HTTP 请求下载代码,无需人工干预。

2.3 浏览器加载 <script src="..."> 的完整过程

1. 浏览器读取本地硬盘上的 .html 文件
2. 解析 HTML,遇到 <script src="https://..."> 这一行
3. 浏览器向该 URL 发起网络请求(GET)
4. 服务器返回 math.js 的源代码(纯文本)
5. 浏览器将这段代码编译并加载到当前页面的 JavaScript 执行环境中
6. 之后在 <script> 或 JS 代码中写 math.evaluate(...) 就能直接调用

整个过程:
  - 没有写入硬盘(浏览器缓存除外)
  - 没有修改系统任何设置
  - 没有注册表、没有环境变量
  - 关掉网页,内存释放

2.4 直观对比表

维度 Python JavaScript(浏览器)
包存储位置 本地硬盘 site-packages/ 互联网 CDN 服务器
获取方式 pip install(下载到本地) <script src="网址">(运行时从网上取)
断网可用 不能(CDN 方式)
需要安装步骤 需要 不需要,浏览器自动处理
版本冲突 经常冲突 不会,每个网页独立执行环境
“环境配置” virtualenv、conda 等 不存在这个概念

三、离线方案:手动下载

如果需要完全离线使用,只需把代码文件保存到本地,改一行路径。

3.1 操作步骤

第一步:在联网状态下,浏览器直接打开 CDN 地址
        https://cdnjs.cloudflare.com/ajax/libs/mathjs/12.4.0/math.min.js
        Ctrl+S 另存为,放到和 HTML 文件同一个文件夹

第二步:HTML 中的引用从 CDN 改为本地路径
        <!-- 从网上借(需联网) -->
        <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjs/12.4.0/math.min.js"></script>

        <!-- 改成用本地的(完全离线) -->
        <script src="math.min.js"></script>

第三步:完事

也可以用命令行下载:

curl -o math.min.js https://cdnjs.cloudflare.com/ajax/libs/mathjs/12.4.0/math.min.js

3.2 最终文件结构

你的文件夹/
├── SciCalc.html      ← 主页面(包含所有界面和逻辑)
└── math.min.js       ← 数学库(约 500KB)

复制这个文件夹到任何电脑,不管有没有网,双击 HTML 就能用。


四、npm install 与手动下载的区别

虽然两者都是”把东西弄到本地”,但做的事情差距很大。

4.1 手动下载

操作:打开网址 → 右键另存为 → 得到 1 个文件
结果:math.min.js(1 个文件,约 500KB)
浏览器能直接用:<script src="math.min.js">
不需要 Node.js 环境

4.2 npm install

操作:命令行执行 npm install mathjs
结果:自动创建 node_modules/ 目录,内含上百个文件
浏览器能直接用:不能
需要 Node.js 环境

npm install 背后做的事情:

  1. 下载 mathjs 包(不是 1 个文件,是散装的模块目录结构)
  2. 创建 node_modules/ 文件夹
  3. 自动检查并下载 mathjs 依赖的其他包
  4. 修改 package.json,记录”装了 mathjs 12.4.0”
  5. 修改 package-lock.json,锁定每个依赖的精确版本
npm install 后的文件结构:
你的文件夹/
├── SciCalc.html
├── package.json
├── package-lock.json
└── node_modules/
    ├── mathjs/
    │   ├── lib/
    │   │   ├── core/
    │   │   │   ├── function/
    │   │   │   │   ├── arithmetic/
    │   │   │   │   │   ├── add.js
    │   │   │   │   │   ├── subtract.js
    │   │   │   │   │   └── ... 几十个文件
    │   │   │   │   ├── matrix/
    │   │   │   │   ├── trigonometry/
    │   │   │   │   └── ...
    │   │   └── type/
    │   └── package.json
    └── 其他被依赖的包...

4.3 为什么浏览器不认识 npm 装的东西

npm 装好的是 Node.js 格式的散装模块,用 require()import 互相引用。浏览器直接打开 HTML 时,不认识 node_modules 目录结构

要让浏览器用 npm 装的包,需要额外的”构建工具”(Vite、Webpack)把散装文件打包成浏览器认识的格式——这对于”复制文件夹就能用”的需求来说,多此一举。

4.4 npm 的正确使用场景

npm 适合正规的前端工程项目(多人协作、几十个依赖、需要版本管理)。流程是:

npm 进货原材料(node_modules/)
    ↓
构建工具加工(Vite / Webpack 打包)
    ↓
产出成品(1 个或几个 .js 文件)
    ↓
浏览器加载成品

对于”单 HTML 文件 + 离线可用”的场景,手动下载是唯一合理的选择。

4.5 对比总结

维度 手动下载 npm install
操作方式 浏览器右键另存为 命令行执行
得到什么 1 个 .min.js 文件 node_modules/ 文件树
文件大小 ~500KB(已压缩) 几 MB(未压缩源码)
浏览器能直接用 不能
依赖管理
需要 Node.js 不需要 需要
适合纯浏览器项目 适合 不适合

五、文件大小:为什么 JS 库这么小

5.1 真实数据

功能 未压缩 .min.js 压缩后
math.js 科学计算 ~2.5MB ~500KB
Chart.js 图表 ~700KB ~200KB
jQuery DOM 操作 ~300KB ~90KB
Tailwind CSS 样式 ~3.8MB ~300KB(精简版)
three.js 3D 渲染 ~1.2MB ~600KB
marked.js Markdown ~40KB ~25KB

math.js 的 500KB 在 JS 库中算偏大的,因为功能确实多。大部分库压缩后只有几十到两百 KB。

5.2 500KB 是什么概念

一张手机随手拍的照片       → 3~5 MB
一页微信朋友圈图片          → 1~2 MB
math.js 压缩文件           → 0.5 MB
一首 MP3 歌曲(128kbps)   → 3~4 MB
一个 10 秒短视频           → 5~20 MB

500KB 比发一张朋友圈图片还小。

5.3 .min.js 做了什么

.min.js 对源码做了三件事,不损失任何功能:

1. 删除所有注释         → 可能减少 30%
2. 删除所有空格和换行   → 可能减少 20%
3. 长变量名改为单字母   → 可能减少 10~20%

示例:
// 未压缩(给人看,~2.5MB)
function add(a, b) {
    // 将两个数相加
    // 参数 a - 第一个数
    // 参数 b - 第二个数
    var result = a + b;
    return result;
}

// 压缩后(给机器看,~0.5MB)
function add(a,b){return a+b}

5.4 网络传输时还会更小

math.min.js 磁盘大小           → 500 KB
实际网络传输(gzip 压缩后)    → ~150 KB

CDN 服务器和浏览器之间自动协商 gzip 压缩,纯文本压缩率极高,实际传输量约为磁盘大小的三分之一。

5.5 为什么比 Python 包小这么多

核心原因:Python 包里装了编译好的机器码,JS 包里只有纯文本。

Python 的科学计算库(NumPy 等)底层用 C 语言编写,pip 安装时下载的是编译好的二进制文件(.so / .pyd),体积大。而且需要为 Windows、Mac、Linux 分别编译不同版本。

JS 的 math.js 从头到尾就是纯文本(JavaScript 源码),用记事本就能打开看。

Python 包 = 买一台组装好的自行车(占地方,拿起来就能骑)
JS 包     = 拿一张自行车图纸(几乎不占地方,但需要有工厂来造)
           而浏览器,就是那个免费的造车工厂

5.6 为什么 JS 纯文本也能跑得快

因为浏览器本身极其庞大(Chrome 几百 MB),其中的 V8 引擎是用 C++ 写的高性能 JIT(即时编译)引擎。V8 会在零点几秒内把 JS 纯文本编译成高度优化的机器码。

Python 模式:Python 解释器(小) + NumPy(自带C发动机) → 30MB + 15MB = 45MB 才能算
JS 模式:    Chrome(自带V8超级发动机,几百MB) + math.js(图纸,0.5MB) → 瞬间编译,开始算

math.js 0.5MB 就能实现接近 NumPy 的功能,不是作者有魔法,而是站着巨人的肩膀上——几百 MB 的浏览器替它把重活都干了。

5.7 pip install numpy 下载的 15MB 里有什么

实际计算用的机器码(C 编译产物)    ~5 MB
C 语言头文件(给开发者参考)        ~3 MB
测试用例                          ~2 MB
文档和元数据                      ~1 MB
多平台版本(Win/Mac/Linux 都打包) ~4 MB

用户只用到了矩阵相加功能,但 15MB 全下载了。而 math.min.js 是精心切割的最终成品,只有纯粹的计算逻辑。


六、浏览器作为运行基座

6.1 核心认知

现代浏览器是一个兼容所有符合语法规则的 .js 文件的巨大运行基座。只要是合法的 JavaScript 代码,扔进浏览器就能跑,不需要额外的编译器、链接器、环境配置。

6.2 浏览器内建的能力

浏览器天然自带了大量能力,JS 库不需要把这些打包进去:

能力 浏览器内建 API Python 需要装的包
画图 Canvas 2D / WebGL matplotlib (~15MB)
网络请求 fetch / XMLHttpRequest requests (~1MB)
JSON 处理 JSON.parse / stringify json(内置)
界面渲染 DOM tkinter / PyQt (~几十MB)
样式系统 CSS 无对应概念
本地存储 localStorage / IndexedDB sqlite3 等

这就是为什么一个 500KB 的 math.js 加上浏览器,就能实现 Python 需要装几十 MB 包才能做到的事。


七、JavaScript 的能力边界

浏览器的设计哲学是:“我允许你在我这里跑代码,但你休想碰我外面的东西。” 这叫沙箱机制

7.1 完全做不到的(安全沙箱的铁壁)

想做的事 为什么做不到
读写本地任意文件 没有文件系统访问权限
调用本地程序(启动 Python、打开 Word) 不能执行系统命令
直接操作硬件(串口、PCIe、底层打印机) 没有硬件驱动接口(USB/蓝牙有受限 API,不通用)
关机、重启、改系统设置 沙箱与操作系统完全隔离
关掉浏览器后继续运行 标签页关闭 → 内存释放 → 代码立刻死亡
做服务端(监听端口、等待连接) 浏览器是客户端,只能主动请求,不能被动监听

这些限制是故意设计的,不是技术做不到。如果网页 JS 能读写硬盘,打开任何网站别人就能偷走文件——这不可接受。

7.2 能做到但很痛苦的(语言设计的历史包袱)

单线程——算力大户的噩梦

Python:开 10 个进程,10 个 CPU 核心一起算
JS(浏览器):只有一个主线程,所有事情排队做

如果算一个 10000×10000 的矩阵求逆:点击”计算” → 主线程开始算 → 整个网页冻死(鼠标点不动、按钮按不了)→ 几秒后算完 → 网页复活。因为画界面和算数学用的是同一个线程。

补救方案是 Web Worker(开后台线程),但 Worker 里不能用 DOM,主线程和 Worker 之间传大数据要拷贝,代码复杂度翻倍。

数字精度——没有原生高精度浮点数

// JavaScript
0.1 + 0.2  // 0.30000000000000004(不是精确的 0.3)

JS 原生只有 64 位双精度浮点数(IEEE 754),没有 Python 的 Decimal 类型。有效数字超过 15 位就不准确了。金融计算(要求分毫不差)或超高精度科学计算会碰到天花板。

异步模型——认知门槛

因为单线程,所有”耗时操作”都必须”挂起”(回调/Promise/async-await),对没有异步经验的人来说是一堵认知墙。

7.3 能做到但有天花板的(科学计算最可能碰到的)

大规模矩阵运算——没有 BLAS 加速

Python NumPy:底层调用 C 语言的 BLAS/LAPACK(Intel/AMD 花几十年优化的库)
              矩阵乘法自动用 CPU 的 SIMD 指令(一次算 8 个数)
              1000×1000 矩阵乘法 → 几毫秒

JS math.js:纯 JavaScript 的 for 循环嵌套实现
            1000×1000 矩阵乘法 → 几百毫秒到几秒
  • 小矩阵(< 500×500):完全没问题
  • 大矩阵(> 2000×2000):明显变慢,可能卡顿
  • 超大规模(深度学习级):纯 JS 基本不可能

符号计算——力不从心

math.js 能做简单的符号求导:derivative("x^3 + sin(x)", "x")3*x^2 + cos(x)

但做不到:

  • 积分出解析式(∫ e^(-x²) dx = ?)❌
  • 解微分方程 ❌
  • 多项式因式分解 ❌
  • 矩阵的 Jordan 标准型 ❌

这些需要专门的计算机代数系统(如 Python 的 SymPy),math.js 的定位只是”增强版计算器”。

7.4 能力边界全景图

         完全做不了                   能做但慢                   轻松搞定
            │                          │                          │
            ▼                          ▼                          ▼
    ┌───────────────┐        ┌─────────────────┐        ┌─────────────────┐
    │ 读写本地文件   │        │ 2000×2000 矩阵  │        │ 100×100 矩阵运算 │
    │ 调用本地程序   │        │ 高精度浮点运算   │        │ 方程求解         │
    │ 关机后继续跑   │        │ 符号积分         │        │ 数值积分/微分    │
    │ 直接操作硬件   │        │ 深度学习训练     │        │ 函数绘图         │
    │               │        │                 │        │ 统计分析         │
    │  这是安全墙    │        │  这是性能墙      │        │  这是主场        │
    └───────────────┘        └─────────────────┘        └─────────────────┘

八、适用场景判断

适合用纯前端做的

  • 计算器、表达式求值
  • 中小规模矩阵运算(< 1000 阶)
  • 数值求解方程
  • 数值积分 / 数值微分
  • 函数绘图
  • 描述性统计、简单回归
  • 教学演示工具
  • 需要”打开即用、零安装”的任何场景
  • 需要美观界面的交互式工具

不适合用纯前端做的

  • 超大规模数值计算(大型 FEM、CFD)
  • 需要高精度浮点的金融计算
  • 符号计算(解析积分、微分方程)
  • 需要读写本地文件的场景
  • 需要长时间后台运行的任务
  • 深度学习模型训练

如果需要突破浏览器限制

想突破的限制 方案 代价
离线使用 手动下载 .min.js 到本地
大规模计算性能 WebAssembly(把 C/Rust 编译成 .wasm) 开发复杂度大幅增加
读写本地文件 File System Access API(仅 Chromium 浏览器) 兼容性差,需要用户授权
后台运行 Service Worker(仅限网页自身范围) 能力极其有限
突破所有限制 用 Electron/Tauri 打包成桌面应用 失去”打开 HTML 即用”的简洁性

九、关键术语速查

术语 一句话解释
CDN 内容分发网络,全球分布的”代码图书馆”,提供公开的 JS/CSS 文件下载
.min.js 压缩版 JS 文件,去掉了注释、空格、缩短了变量名,体积更小,功能不变
gzip 一种文本压缩格式,CDN 传输时自动使用,能把文本再压缩到原来的 1/3
沙箱 浏览器的安全隔离机制,JS 代码只能在内部分配的内存中运行,不能接触外部系统
V8 Chrome 内置的 JavaScript 引擎,用 C++ 写的,能把 JS 即时编译成高速机器码
JIT Just-In-Time,即时编译,运行时把代码编译成机器码(区别于提前编译 AOT)
Web Worker 浏览器提供的后台线程 API,可以把计算放到后台,避免界面卡死
SIMD 单指令多数据流,CPU 的一次指令同时处理多个数据,NumPy 底层用它加速
BLAS/LAPACK 底层线性代数计算库,几十年优化的成果,NumPy 底层调用的就是它们
Node.js 让 JavaScript 能脱离浏览器在命令行运行的环境,有文件系统、网络等能力
npm Node.js 的包管理器,相当于 Python 的 pip

文档整理自对话记录,作为个人知识库存档。 ```

直接复制保存为 .md 文件即可。如果用 VS Code 或 Typora 打开,表格和代码块都会有正确的渲染效果。