So sánh thư viện phân tích và xử lý JSON
Kết luận: API gốc nhanh nhất, parser dung sai cho offset. Hãy chọn theo ba điều: định vị lỗi, có giữ văn bản gốc không, và ranh giới có tường minh không.

Kết luận: hãy phân loại nhu cầu trước, rồi mới so sánh cách hiện thực — dùng JSON.parse gốc cho giá trị chỉ đọc, jsonc-parser khi cần offset hoặc phải giữ định dạng gốc, và chỉ thêm thư viện truy vấn hay patch ở nơi thực sự cần; lazy-load thư viện lớn theo từng trang và loại bỏ những thư viện không còn được bảo trì.
Mọi thư viện đều tự nhận là "nhanh, nhỏ và đầy đủ". Thứ thực sự phân biệt chúng là lượng thông tin chúng có thể cho bạn khi có gì đó sai.
1. Bốn loại theo mục đích
| Loại | Thư viện tiêu biểu | Nó giải quyết điều gì |
|---|---|---|
| Phân tích chuẩn | JSON.parse / JSON.stringify |
Cú pháp ↔ object, tốc độ là ưu tiên |
| Phân tích dung sai + chỉnh sửa | jsonc-parser, json5 |
Đầu vào có comment, lỗi chính xác đến offset, chỉnh sửa giữ được định dạng |
| Truy vấn | jsonpath-plus, jsonpath |
Chọn node theo biểu thức |
| Thay đổi | fast-json-patch, immer |
Sinh/áp dụng patch, cập nhật bất biến |
Hãy nhận diện bạn đang ở loại nào trước, rồi mới so sánh các cách hiện thực cụ thể — nếu không rất dễ dùng thư viện truy vấn để làm việc của một parser.
2. So sánh song song
| Thư viện | Định vị lỗi | Dung sai (comment/dấu phẩy cuối) | Giữ định dạng gốc | Tình huống phù hợp |
|---|---|---|---|---|
JSON.parse |
Chỉ thông báo và vị trí (tùy engine) | ✗ | ✗ | Phân tích mặc định, dữ liệu API |
jsonc-parser |
offset chính xác + mã lỗi |
✓ | ✓ (modify + applyEdits) |
Trình soạn thảo, tệp cấu hình |
json5 |
Thông tin dòng và cột | ✓ (dễ dãi hơn) | ✗ | Đọc cấu hình JSON5 |
jsonlint |
Thông tin dòng và cột | ✗ | ✗ | Chỉ để tham khảo, không được bảo trì tích cực |
jsonpath-plus |
Lỗi cú pháp biểu thức | — | — | Truy vấn theo biểu thức |
fast-json-patch |
Lỗi ở mức thao tác | — | — | Sinh và áp dụng patch |
lz-string |
— | — | — | Nén JSON vào URL |
Thông báo lỗi của JSON.parse khác nhau rất nhiều giữa các engine. V8 tạo ra đại khái
Unexpected token } in JSON at position 42, nhưng vị trí có chính xác hay không còn tùy phiên bản engine;
jsonc-parser thay vào đó trả về { error, offset, length } có cấu trúc và ổn định, phù hợp để làm marker trong trình soạn thảo.
3. Bốn điểm quyết định then chốt
3.1 Bạn có cần offset không
Nếu bạn đang dựng trình soạn thảo và muốn "bấm vào lỗi để nhảy tới dòng tương ứng", bạn buộc phải có offset. Bài kiểm tra rất đơn giản: nếu thông báo lỗi của bạn chỉ có thể in "invalid JSON", người dùng sẽ phải tự đi tìm.
import { parse, printParseErrorCode } from 'jsonc-parser';
const errors: Array<{ error: number; offset: number; length: number }> = [];
parse(text, errors, { allowTrailingComma: true, disallowComments: false });
if (errors.length > 0) {
const firstError = errors[0];
console.error(`${printParseErrorCode(firstError.error)} at offset ${firstError.offset}`);
}
3.2 Bạn có cần giữ văn bản gốc không
Chỉ đọc giá trị → parser nào cũng được. "Đổi một trường và giữ mọi thứ khác y hệt" → bạn buộc phải dùng API kiểu chỉnh sửa, không phải "parse → sửa object → serialize".
Cách sau làm mất: comment, thứ tự khóa (trong một số cách hiện thực), kiểu thụt lề, cách viết literal số (1e3 thành 1000), và dạng escape (\u4e2d thành ký tự thật).
3.3 Hành vi biên có tường minh không
Trước khi chọn thư viện, hãy kiểm tra tài liệu ba điều:
- Khóa trùng được xử lý thế nào (giữ cái cuối / báo lỗi);
- Số nguyên lớn có mất độ chính xác không (hầu hết thư viện JS đều có, vì đều đi qua
Number); - Phạm vi hỗ trợ cho BOM, comment và dấu phẩy cuối.
Nếu không có tài liệu, hãy viết một mẫu nhỏ và tự kiểm tra. Điều đó đáng tin hơn đọc README.
3.4 Tình trạng bảo trì
Rủi ro của một thư viện JSON không phải là thiếu tính năng, mà là bị bỏ quên lâu dài: sẽ không còn ai phát hành bản vá bảo mật (prototype pollution, ReDoS) nữa.
4. So sánh với ngôn ngữ khác
| Ngôn ngữ | Thư viện chuẩn / thư viện chính | Khác biệt chính |
|---|---|---|
| JavaScript | JSON.parse |
Mọi số đều là double precision |
| TypeScript | Như trên + jsonc-parser / zod |
Kiểu chỉ tồn tại ở thời điểm biên dịch |
| Go | encoding/json |
Mặc định float64, dùng UseNumber() để giữ độ chính xác; json.RawMessage cho phân tích hoãn |
| Java | Jackson / Gson / Moshi | Với Jackson, chú ý rủi ro khi bật default typing |
| Python | json / orjson |
parse_float=Decimal giữ độ chính xác; orjson nhanh hơn nhưng không hỗ trợ mọi kiểu |
| Rust | serde_json |
Giải tuần tự có kiểu mạnh; tính năng arbitrary_precision giữ độ chính xác |
| C++ | simdjson / RapidJSON | simdjson nhắm tới thông lượng phân tích, RapidJSON tổng quát hơn |
Khi trao đổi dữ liệu giữa các ngôn ngữ, thứ dễ vấp nhất vẫn là độ chính xác số và định dạng thời gian; việc chọn thư viện chỉ có thể giảm nhẹ chứ không loại bỏ được.
5. Tổ hợp điển hình
Phương án 1: trang công cụ (phía trình duyệt)
Parsing and error location: jsonc-parser
Editor: CodeMirror 6 + @codemirror/lang-json
Query: jsonpath-plus
Patch: fast-json-patch
Share links: lz-string
Điểm đặc trưng của tổ hợp này là mọi thứ chạy cục bộ và không dữ liệu nào bị tải lên, phù hợp với kỳ vọng riêng tư của một trang công cụ.
Phương án 2: gateway API phía máy chủ
Validation: Ajv (compile the schema once, reuse it)
Parsing: native JSON.parse (together with a body size limit)
Deferred parsing of large fields: keep the raw string, parse only when needed
Đừng đưa thư viện truy vấn/patch vào tầng gateway để hiện thực logic nghiệp vụ — đó là việc của tầng nghiệp vụ.
Phương án 3: CLI và script
Pick fields: jq
Format conversion: yq / dasel
Interactive browsing: jless
Batch validation: ajv-cli
6. Tác động thật của kích thước bundle và hiệu năng
jsonc-parserrất nhỏ và phù hợp cho bundle chính;json5lớn hơnjsonc-parsermột chút vì hỗ trợ nhiều cú pháp hơn;jsonpath-plusbao gồm cả đánh giá biểu thức và lớn hơn rõ rệt, nên nên lazy-load theo từng trang;fast-json-patchcỡ trung bình và chỉ cần khi bạn có tính năng so sánh.
Việc tối ưu rất thẳng: import động theo từng trang, và đừng đặt chúng vào chunk màn hình đầu.
const { JSONPath } = await import('jsonpath-plus');
7. Danh sách kiểm tra
- [ ] Chọn thư viện theo mục đích; đừng dùng thư viện truy vấn để phân tích;
- [ ] Dùng
jsonc-parserkhi cần định vị lỗi chính xác; - [ ] Dùng API kiểu chỉnh sửa khi phải giữ comment và định dạng;
- [ ] Thử trên thực tế ba hành vi biên: khóa trùng, số nguyên lớn và BOM;
- [ ] Theo dõi tình trạng bảo trì và khuyến cáo bảo mật của thư viện;
- [ ] Import động các thư viện lớn theo nhu cầu.
FAQ
Làm sao chọn thư viện JSON phù hợp quy mô dự án?
Công cụ nhỏ chỉ đọc dữ liệu API có thể dùng JSON.parse gốc. Dự án cần định vị lỗi chuẩn trình soạn thảo hoặc phải giữ định dạng gốc nên dùng jsonc-parser. Gateway phía máy chủ chỉ cần kiểm chứng và phân tích, để thư viện truy vấn và patch cho tầng nghiệp vụ, còn script CLI có thể dùng trực tiếp jq, yq và ajv-cli.
Vì sao tình trạng bảo trì quan trọng hơn số tính năng?
Rủi ro thật của một thư viện JSON là bị bỏ quên lâu dài, không phải thiếu tính năng: sẽ không còn ai phát hành bản vá bảo mật cho prototype pollution hay ReDoS. Danh sách tính năng đầy đủ đến đâu thì một thư viện đã ngừng phát triển vẫn khiến bạn phải tự vá. Hãy coi mức độ bảo trì và các khuyến cáo bảo mật là tiêu chí cứng thay vì chỉ so bảng tính năng.
Có nên dùng JSON.parse để đổi một trường mà vẫn giữ comment và thụt lề?
Không. Phân tích, sửa object, rồi tuần tự hoá sẽ làm mất comment, thứ tự khóa, kiểu thụt lề, cách viết literal số (1e3 thành 1000), và dạng escape (\u4e2d thành ký tự thật). Đổi một trường trong khi giữ mọi thứ khác nguyên vẹn cần API kiểu chỉnh sửa như modify và applyEdits trong jsonc-parser.