对于小负载, fast-json-stringify比JSON.stringify()
快得多。随着有效负载的增加,其性能优势会缩小。它与flatstr配合得很好,后者会触发 V8 优化,从而在最终将字符串转换为Buffer
时提高性能。
fast-json-stringify 需要 JSON Schema Draft 7 输入来生成快速stringify
函数。
EX41S-SSD, Intel Core i7, 4Ghz, 64GB RAM, 4C/8T, SSD
。v18.12.1
FJS creation x 4,129 ops/sec ±0.82% (92 runs sampled)
CJS creation x 184,196 ops/sec ±0.12% (97 runs sampled)
AJV Serialize creation x 61,130,591 ops/sec ±0.40% (92 runs sampled)
JSON.stringify array x 5,057 ops/sec ±0.10% (100 runs sampled)
fast-json-stringify array default x 6,243 ops/sec ±0.14% (98 runs sampled)
fast-json-stringify array json-stringify x 6,261 ops/sec ±0.30% (99 runs sampled)
compile-json-stringify array x 6,842 ops/sec ±0.18% (96 runs sampled)
AJV Serialize array x 6,964 ops/sec ±0.11% (95 runs sampled)
JSON.stringify large array x 248 ops/sec ±0.07% (90 runs sampled)
fast-json-stringify large array default x 99.96 ops/sec ±0.22% (74 runs sampled)
fast-json-stringify large array json-stringify x 248 ops/sec ±0.07% (90 runs sampled)
compile-json-stringify large array x 317 ops/sec ±0.09% (89 runs sampled)
AJV Serialize large array x 111 ops/sec ±0.07% (33 runs sampled)
JSON.stringify long string x 16,002 ops/sec ±0.09% (98 runs sampled)
fast-json-stringify long string x 15,979 ops/sec ±0.09% (96 runs sampled)
compile-json-stringify long string x 15,952 ops/sec ±0.31% (97 runs sampled)
AJV Serialize long string x 21,416 ops/sec ±0.08% (98 runs sampled)
JSON.stringify short string x 12,944,272 ops/sec ±0.09% (96 runs sampled)
fast-json-stringify short string x 30,585,790 ops/sec ±0.27% (97 runs sampled)
compile-json-stringify short string x 30,656,406 ops/sec ±0.12% (96 runs sampled)
AJV Serialize short string x 30,406,785 ops/sec ±0.37% (96 runs sampled)
JSON.stringify obj x 3,153,043 ops/sec ±0.33% (99 runs sampled)
fast-json-stringify obj x 6,866,434 ops/sec ±0.11% (100 runs sampled)
compile-json-stringify obj x 15,886,723 ops/sec ±0.15% (98 runs sampled)
AJV Serialize obj x 8,969,043 ops/sec ±0.36% (97 runs sampled)
JSON stringify date x 1,126,547 ops/sec ±0.09% (97 runs sampled)
fast-json-stringify date format x 1,836,188 ops/sec ±0.12% (99 runs sampled)
compile-json-stringify date format x 1,125,735 ops/sec ±0.19% (98 runs sampled)
Example
Options
API
fastJsonStringify
Specific use cases
Required
Missing fields
Pattern Properties
Additional Properties
AnyOf
和OneOf
Reuse - $ref
Long integers
Integers
Nullable
Large Arrays
Security Notice
Debug Mode
Standalone Mode
Acknowledgements
License
在 RunKit 上尝试一下:https://runkit.com/npm/fast-json-stringify
const fastJson = require ( 'fast-json-stringify' )
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
firstName : {
type : 'string'
} ,
lastName : {
type : 'string'
} ,
age : {
description : 'Age in years' ,
type : 'integer'
} ,
reg : {
type : 'string'
}
}
} )
console . log ( stringify ( {
firstName : 'Matteo' ,
lastName : 'Collina' ,
age : 32 ,
reg : / "([^"]|\")*" /
} ) )
或者,您可以向fast-json-stringify
提供一个选项对象作为第二个参数:
const fastJson = require ( 'fast-json-stringify' )
const stringify = fastJson ( mySchema , {
schema : { ... } ,
ajv : { ... } ,
rounding : 'ceil'
} )
schema
:通过 $ref 属性引用外部模式。更多详情ajv
:ajv v8 实例的那些需要ajv
属性的设置。更多详情rounding
:设置integer
类型在非整数时如何四舍五入。更多详情largeArrayMechanism
:设置用于处理大型(默认为20000
或更多项)数组的机制。更多详情基于 jsonschema 草案 7 规范构建stringify()
函数。
支持的类型:
'string'
'integer'
'number'
'array'
'object'
'boolean'
'null'
还有嵌套的。
实例 | 序列化为 |
---|---|
Date | 通过toISOString() string |
RegExp | string |
BigInt | 通过toString integer |
支持 JSON Schema 内置日期格式,并将序列化为:
格式 | 序列化格式示例 |
---|---|
date-time | 2020-04-03T09:11:08.615Z |
date | 2020-04-03 |
time | 09:11:08 |
注意:如果是字符串格式的日期而不是日期对象,则不会对其进行任何操作。它应该被正确格式化。
日期对象示例:
const stringify = fastJson ( {
title : 'Example Schema with string date-time field' ,
type : 'string' ,
format : 'date-time'
} )
const date = new Date ( )
console . log ( stringify ( date ) ) // '"YYYY-MM-DDTHH:mm:ss.sssZ"'
您可以根据架构中的需要设置对象的特定字段,方法是将字段名称添加到架构中required
数组内。例子:
const schema = {
title : 'Example Schema with required field' ,
type : 'object' ,
properties : {
nickname : {
type : 'string'
} ,
mail : {
type : 'string'
}
} ,
required : [ 'mail' ]
}
如果要 stringify 的对象缺少必需的字段, fast-json-stringify
将抛出错误。
如果某个字段存在于模式中(并且不是必需的),但它不存在于要字符串化的对象中, fast-json-stringify
不会将其写入最终字符串中。例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
nickname : {
type : 'string'
} ,
mail : {
type : 'string'
}
}
} )
const obj = {
mail : '[email protected]'
}
console . log ( stringify ( obj ) ) // '{"mail":"[email protected]"}'
fast-json-stringify
支持default
jsonschema 键,以便在undefined
或不存在的情况下序列化值。
例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
nickname : {
type : 'string' ,
default : 'the default string'
}
}
} )
console . log ( stringify ( { } ) ) // '{"nickname":"the default string"}'
console . log ( stringify ( { nickname : 'my-nickname' } ) ) // '{"nickname":"my-nickname"}'
fast-json-stringify
支持 JSON 模式定义的模式属性。 patternProperties必须是一个对象,其中键是有效的正则表达式,值是一个对象,声明方式如下: { type: 'type' }
。 patternProperties仅适用于属性对象中未明确列出的属性。例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
nickname : {
type : 'string'
}
} ,
patternProperties : {
'num' : {
type : 'number'
} ,
'.*foo$' : {
type : 'string'
}
}
} )
const obj = {
nickname : 'nick' ,
matchfoo : 42 ,
otherfoo : 'str' ,
matchnum : 3
}
console . log ( stringify ( obj ) ) // '{"matchfoo":"42","otherfoo":"str","matchnum":3,"nickname":"nick"}'
fast-json-stringify
支持 JSON 模式定义的其他属性。 extraProperties必须是一个对象或布尔值,以这种方式声明: { type: 'type' }
。 extraProperties仅适用于properties和patternProperties对象中未显式列出的属性。
如果additionalProperties不存在或设置为false
,则属性和patternProperties对象中未显式列出的每个属性都将被忽略,如缺少字段中所述。缺失的字段将被忽略,以避免在序列化之前重写对象。然而,其他模式规则也会引发类似的情况。如果extraProperties设置为true
, JSON.stringify
将使用它来字符串化附加属性。如果您想获得最佳性能,我们强烈建议您尽可能使用固定架构。附加属性将始终在对象的末尾进行序列化。例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
nickname : {
type : 'string'
}
} ,
patternProperties : {
'num' : {
type : 'number'
} ,
'.*foo$' : {
type : 'string'
}
} ,
additionalProperties : {
type : 'string'
}
} )
const obj = {
nickname : 'nick' ,
matchfoo : 42 ,
otherfoo : 'str' ,
matchnum : 3 ,
nomatchstr : 'valar morghulis' ,
nomatchint : 313
}
console . log ( stringify ( obj ) ) // '{"nickname":"nick","matchfoo":"42","otherfoo":"str","matchnum":3,"nomatchstr":"valar morghulis",nomatchint:"313"}'
fast-json-stringify
支持 JSON 模式定义的anyOf和oneOf关键字。两者都必须是有效 JSON 模式的数组。不同的模式将按指定的顺序进行测试。 stringify
在找到匹配之前尝试的模式越多,速度就越慢。
anyOf和oneOf使用 ajv 作为 JSON 模式验证器来查找与数据匹配的模式。这会对性能产生影响——仅将其用作最后的手段。
例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
'undecidedType' : {
'anyOf' : [ {
type : 'string'
} , {
type : 'boolean'
} ]
}
}
} )
为anyOf指定对象 JSON 架构时,添加所需的验证关键字以仅匹配具有所需属性的对象。
例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'array' ,
items : {
anyOf : [
{
type : 'object' ,
properties : {
savedId : { type : 'string' }
} ,
// without "required" validation any object will match
required : [ 'savedId' ]
} ,
{
type : 'object' ,
properties : {
error : { type : 'string' }
} ,
required : [ 'error' ]
}
]
}
} )
fast-json-stringify
支持if/then/else
jsonschema 功能。请参阅 ajv 文档。
例子:
const stringify = fastJson ( {
'type' : 'object' ,
'properties' : {
} ,
'if' : {
'properties' : {
'kind' : { 'type' : 'string' , 'enum' : [ 'foobar' ] }
}
} ,
'then' : {
'properties' : {
'kind' : { 'type' : 'string' , 'enum' : [ 'foobar' ] } ,
'foo' : { 'type' : 'string' } ,
'bar' : { 'type' : 'number' }
}
} ,
'else' : {
'properties' : {
'kind' : { 'type' : 'string' , 'enum' : [ 'greeting' ] } ,
'hi' : { 'type' : 'string' } ,
'hello' : { 'type' : 'number' }
}
}
} )
console . log ( stringify ( {
kind : 'greeting' ,
foo : 'FOO' ,
bar : 42 ,
hi : 'HI' ,
hello : 45
} ) ) // {"kind":"greeting","hi":"HI","hello":45}
console . log ( stringify ( {
kind : 'foobar' ,
foo : 'FOO' ,
bar : 42 ,
hi : 'HI' ,
hello : 45
} ) ) // {"kind":"foobar","foo":"FOO","bar":42}
注意不要声明属性两次,否则您将打印两次!
如果要重用值的定义,可以使用属性$ref
。 $ref
的值必须是 JSON Pointer 格式的字符串。例子:
const schema = {
title : 'Example Schema' ,
definitions : {
num : {
type : 'object' ,
properties : {
int : {
type : 'integer'
}
}
} ,
str : {
type : 'string'
}
} ,
type : 'object' ,
properties : {
nickname : {
$ref : '#/definitions/str'
}
} ,
patternProperties : {
'num' : {
$ref : '#/definitions/num'
}
} ,
additionalProperties : {
$ref : '#/definitions/def'
}
}
const stringify = fastJson ( schema )
如果需要使用外部定义,可以将其作为选项传递给fast-json-stringify
。例子:
const schema = {
title : 'Example Schema' ,
type : 'object' ,
properties : {
nickname : {
$ref : 'strings#/definitions/str'
}
} ,
patternProperties : {
'num' : {
$ref : 'numbers#/definitions/num'
}
} ,
additionalProperties : {
$ref : 'strings#/definitions/def'
}
}
const externalSchema = {
numbers : {
definitions : {
num : {
type : 'object' ,
properties : {
int : {
type : 'integer'
}
}
}
}
} ,
strings : require ( './string-def.json' )
}
const stringify = fastJson ( schema , { schema : externalSchema } )
外部定义也可以互相引用。例子:
const schema = {
title : 'Example Schema' ,
type : 'object' ,
properties : {
foo : {
$ref : 'strings#/definitions/foo'
}
}
}
const externalSchema = {
strings : {
definitions : {
foo : {
$ref : 'things#/definitions/foo'
}
}
} ,
things : {
definitions : {
foo : {
type : 'string'
}
}
}
}
const stringify = fastJson ( schema , { schema : externalSchema } )
默认情况下,库将自动处理 BigInt。
如果提供浮点数,则type: integer
属性将被截断。您可以使用接受round
、 ceil
、 floor
或trunc
rounding
选项来自定义此行为。默认为trunc
:
const stringify = fastJson ( schema , { rounding : 'ceil' } )
根据 Open API 3.0 规范,可以为 null 的值必须声明nullable
。
const stringify = fastJson ( {
'title' : 'Nullable schema' ,
'type' : 'object' ,
'nullable' : true ,
'properties' : {
'product' : {
'nullable' : true ,
'type' : 'object' ,
'properties' : {
'name' : {
'type' : 'string'
}
}
}
}
} )
console . log ( stringify ( { product : { name : "hello" } } ) ) // "{"product":{"name":"hello"}}"
console . log ( stringify ( { product : null } ) ) // "{"product":null}"
console . log ( stringify ( null ) ) // null
否则,将按如下方式强制强制 null 值,而不是引发错误:
integer
-> 0
number
-> 0
string
-> ""
boolean
-> false
object
-> {}
array
-> []
在本文档的范围内,大型数组定义为默认包含20000
或更多元素的数组。该值可以通过选项参数largeArraySize
进行调整。
在某些时候, fast-json-stringify
使用默认机制处理数组所造成的开销开始呈指数级增长,导致整体执行速度变慢。
为了改进,用户可以设置largeArrayMechanism
和largeArraySize
选项。
largeArrayMechanism
的默认值是default
。它的有效值为:
default
- 此选项是性能和功能集之间的折衷方案,仍然提供此库中的预期功能,但放弃一些可能的性能增益。设置此选项后,大型数组将通过使用Array.join
连接其字符串化元素而不是字符串连接来进行字符串化,以获得更好的性能json-stringify
- 此选项将完全删除对大型数组中模式验证的支持。通过这样做,前面提到的开销就被消除了,从而大大缩短了执行时间。请注意,对于不太大的数组,行为没有变化largeArraySize
的默认值为20000
。它的有效值为类似整数的值,例如:
20000
2e4
'20000'
'2e4'
-请注意这将转换为2
,而不是20000
1.5
-请注意这将转换为1
默认情况下,该库会对所有字符串进行转义。使用“不安全”格式,字符串不会被转义。这存在潜在危险的安全问题。仅当您确定数据不需要转义时才可以使用它。优点是性能显着提高。
例子:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
'code' : {
type : 'string' ,
format 'unsafe'
}
}
} )
作为参考,这里有一些对三种机制进行比较的基准。在旧机器上进行的基准测试。
ST1000LM024 HN-M 1TB HDD, Intel Core i7-3610QM @ 2.3GHz, 12GB RAM, 4C/8T
。v16.13.1
JSON.stringify large array x 157 ops/sec ±0.73% (86 runs sampled)
fast-json-stringify large array default x 48.72 ops/sec ±4.92% (48 runs sampled)
fast-json-stringify large array json-stringify x 157 ops/sec ±0.76% (86 runs sampled)
compile-json-stringify large array x 175 ops/sec ±4.47% (79 runs sampled)
AJV Serialize large array x 58.76 ops/sec ±4.59% (60 runs sampled)
将模式定义视为应用程序代码,使用用户提供的模式是不安全的。
为了实现低成本和高性能编辑, fast-json-stringify
在初始化时创建并编译一个函数(使用Function
构造函数)。虽然当前已验证schema
是否存在任何开发人员错误,但不能保证提供用户生成的架构不会使您的应用程序遭受远程攻击。
用户有责任发送可信数据。 fast-json-stringify
保证仅当您的输入与模式匹配或可以强制为模式时,您才会获得有效的输出。如果您的输入与架构不匹配,您将得到未定义的行为。
可以在开发过程中激活调试模式,以了解当事情未按预期工作时发生的情况。
const debugCompiled = fastJson ( {
title : 'default string' ,
type : 'object' ,
properties : {
firstName : {
type : 'string'
}
}
} , { mode : 'debug' } )
console . log ( debugCompiled ) // it is a object contain code, ajv instance
const rawString = debugCompiled . code // it is the generated code
console . log ( rawString )
const stringify = fastJson . restore ( debugCompiled ) // use the generated string to get back the `stringify` function
console . log ( stringify ( { firstName : 'Foo' , surname : 'bar' } ) ) // '{"firstName":"Foo"}'
Standalone模式用于编译node
本身可以直接运行的代码。您需要安装fast-json-stringify
才能使独立代码正常工作。
const fs = require ( 'fs' )
const code = fastJson ( {
title : 'default string' ,
type : 'object' ,
properties : {
firstName : {
type : 'string'
}
}
} , { mode : 'standalone' } )
fs . writeFileSync ( 'stringify.js' , code )
const stringify = require ( 'stringify.js' )
console . log ( stringify ( { firstName : 'Foo' , surname : 'bar' } ) ) // '{"firstName":"Foo"}'
该项目得到了nearForm 的大力赞助。
麻省理工学院