fast-json-stringify é significativamente mais rápido que JSON.stringify()
para cargas pequenas. Sua vantagem de desempenho diminui à medida que sua carga útil aumenta. Ele combina bem com flatstr , que aciona uma otimização V8 que melhora o desempenho ao eventualmente converter a string em um Buffer
.
fast-json-stringify requer uma entrada JSON Schema Draft 7 para gerar uma função stringify
rápida.
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
e OneOf
Reuse - $ref
Long integers
Integers
Nullable
Large Arrays
Security Notice
Debug Mode
Standalone Mode
Acknowledgements
License
Experimente no 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 : / "([^"]|\")*" /
} ) )
Opcionalmente, você pode fornecer fast-json-stringify
um objeto de opção como segundo parâmetro:
const fastJson = require ( 'fast-json-stringify' )
const stringify = fastJson ( mySchema , {
schema : { ... } ,
ajv : { ... } ,
rounding : 'ceil'
} )
schema
: referências de esquemas externos pela propriedade $ref. Mais detalhesajv
: configurações da instância ajv v8 para as propriedades que exigem ajv
. Mais detalhesrounding
: configure como os tipos integer
serão arredondados quando não forem inteiros. Mais detalheslargeArrayMechanism
: define o mecanismo que deve ser usado para lidar com matrizes grandes (por padrão, 20000
ou mais itens). Mais detalhes Crie uma função stringify()
com base nas especificações do rascunho 7 do jsonschema.
Tipos suportados:
'string'
'integer'
'number'
'array'
'object'
'boolean'
'null'
E os aninhados também.
Exemplo | Serializado como |
---|---|
Date | string via toISOString() |
RegExp | string |
BigInt | integer via toString |
Os formatos integrados do esquema JSON para datas são suportados e serão serializados como:
Formatar | Exemplo de formato serializado |
---|---|
date-time | 2020-04-03T09:11:08.615Z |
date | 2020-04-03 |
time | 09:11:08 |
Nota : No caso de Data formatada em string e não de Objeto Data, não haverá manipulação sobre ela. Deve estar formatado corretamente.
Exemplo com um objeto Date:
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"'
Você pode definir campos específicos de um objeto conforme necessário em seu esquema adicionando o nome do campo dentro da matriz required
em seu esquema. Exemplo:
const schema = {
title : 'Example Schema with required field' ,
type : 'object' ,
properties : {
nickname : {
type : 'string'
} ,
mail : {
type : 'string'
}
} ,
required : [ 'mail' ]
}
Se o objeto a ser stringify não tiver os campos obrigatórios, fast-json-stringify
gerará um erro.
Se um campo estiver presente no esquema (e não for obrigatório), mas não estiver presente no objeto a ser stringificado, fast-json-stringify
não o escreverá na string final. Exemplo:
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
suporta a chave jsonschema default
para serializar um valor se ele for undefined
ou não estiver presente.
Exemplo:
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
oferece suporte a propriedades padrão conforme definido pelo esquema JSON. patternProperties deve ser um objeto, onde a chave é uma regex válida e o valor é um objeto, declarado desta forma: { type: 'type' }
. patternProperties funcionará apenas para as propriedades que não estão explicitamente listadas no objeto de propriedades. Exemplo:
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
suporta propriedades adicionais conforme definido pelo esquema JSON. adicionalProperties deve ser um objeto ou booleano, declarado desta forma: { type: 'type' }
. adicionalProperties funcionará apenas para as propriedades que não estão explicitamente listadas nas propriedades e nos objetos patternProperties .
Se adicionalProperties não estiver presente ou estiver configurado como false
, todas as propriedades que não estiverem explicitamente listadas nos objetos properties e patternProperties serão ignoradas, conforme descrito em Campos ausentes. Os campos ausentes são ignorados para evitar a necessidade de reescrever objetos antes da serialização. No entanto, outras regras de esquema ocorreriam em situações semelhantes. Se adicionalProperties estiver definido como true
, ele será usado por JSON.stringify
para restringir as propriedades adicionais. Se você deseja obter desempenho máximo, recomendamos fortemente que você use um esquema fixo sempre que possível. As propriedades adicionais sempre serão serializadas no final do objeto. Exemplo:
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
suporta as palavras-chave anyOf e oneOf conforme definido pelo esquema JSON. Ambos devem ser uma matriz de esquemas JSON válidos. Os diferentes esquemas serão testados na ordem especificada. Quanto mais esquemas stringify
tiver que tentar antes de encontrar uma correspondência, mais lento será.
anyOf e oneOf usam ajv como um validador de esquema JSON para encontrar o esquema que corresponde aos dados. Isso tem impacto no desempenho – use-o apenas como último recurso.
Exemplo:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
'undecidedType' : {
'anyOf' : [ {
type : 'string'
} , {
type : 'boolean'
} ]
}
}
} )
Ao especificar esquemas JSON de objeto para anyOf , adicione a palavra-chave de validação necessária para corresponder apenas os objetos às propriedades desejadas.
Exemplo:
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
suporta o recurso if/then/else
jsonschema. Consulte a documentação do ajv.
Exemplo:
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}
NB Não declare as propriedades duas vezes ou você as imprimirá duas vezes!
Se quiser reutilizar a definição de um valor, você pode usar a propriedade $ref
. O valor de $ref
deve ser uma string no formato JSON Pointer. Exemplo:
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 )
Se precisar usar uma definição externa, você pode passá-la como uma opção para fast-json-stringify
. Exemplo:
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 } )
As definições externas também podem fazer referência umas às outras. Exemplo:
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 } )
Por padrão, a biblioteca irá lidar automaticamente com BigInt.
A propriedade type: integer
será truncada se um ponto flutuante for fornecido. Você pode personalizar esse comportamento com a opção rounding
que aceitará round
, ceil
, floor
ou trunc
. O padrão é trunc
:
const stringify = fastJson ( schema , { rounding : 'ceil' } )
De acordo com a especificação Open API 3.0, um valor que pode ser null deve ser declarado 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
Caso contrário, em vez de gerar um erro, os valores nulos serão forçados da seguinte forma:
integer
-> 0
number
-> 0
string
-> ""
boolean
-> false
object
-> {}
array
-> []
Matrizes grandes são, para o escopo deste documento, definidas como matrizes contendo, por padrão, 20000
elementos ou mais. Esse valor pode ser ajustado através do parâmetro de opção largeArraySize
.
Em algum ponto, a sobrecarga causada pelo mecanismo padrão usado pelo fast-json-stringify
para lidar com arrays começa a aumentar exponencialmente, levando a execuções gerais lentas.
Para melhorar isso o usuário pode definir as opções largeArrayMechanism
e largeArraySize
.
O valor padrão de largeArrayMechanism
é default
. Os valores válidos para isso são:
default
- Esta opção é um compromisso entre desempenho e conjunto de recursos, ainda fornecendo a funcionalidade esperada desta biblioteca, mas abrindo mão de algum possível ganho de desempenho. Com esta opção definida, arrays grandes seriam stringificados juntando seus elementos stringificados usando Array.join
em vez de concatenação de strings para melhor desempenhojson-stringify
- Esta opção removerá completamente o suporte para validação de esquema em grandes matrizes . Ao fazer isso, a sobrecarga mencionada anteriormente é anulada, melhorando bastante o tempo de execução. Lembre-se de que não há mudança no comportamento de arrays não considerados grandes O valor padrão de largeArraySize
é 20000
. Os valores válidos para ele são valores semelhantes a números inteiros, como:
20000
2e4
'20000'
'2e4'
- observe que isso será convertido para 2
, não 20000
1.5
- observe que isso será convertido para 1
Por padrão, a biblioteca escapa de todas as strings. Com o formato 'inseguro', a string não tem escape. Isso tem um problema de segurança potencialmente perigoso. Você só poderá usá-lo se tiver certeza de que seus dados não precisam ser escapados. A vantagem é uma melhoria significativa de desempenho.
Exemplo:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
'code' : {
type : 'string' ,
format 'unsafe'
}
}
} )
Para referência, aqui vão alguns benchmarks para comparação entre os três mecanismos. Benchmarks realizados em uma máquina antiga.
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)
Trate a definição de esquema como código de aplicativo; não é seguro usar esquemas fornecidos pelo usuário.
Para obter redação de baixo custo e alto desempenho fast-json-stringify
cria e compila uma função (usando o construtor Function
) na inicialização. Embora o schema
esteja atualmente validado para quaisquer erros do desenvolvedor, não há garantia de que o fornecimento do esquema gerado pelo usuário não possa expor seu aplicativo a ataques remotos.
Os usuários são responsáveis pelo envio de dados confiáveis. fast-json-stringify
garante que você obterá uma saída válida somente se sua entrada corresponder ao esquema ou puder ser coagida ao esquema. Se sua entrada não corresponder ao esquema, você obterá um comportamento indefinido.
O modo de depuração pode ser ativado durante o desenvolvimento para entender o que está acontecendo quando as coisas não funcionam como você espera.
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"}'
O modo autônomo é usado para compilar o código que pode ser executado diretamente pelo próprio node
. Você precisa ter fast-json-stringify
instalado para que o código independente funcione.
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"}'
Este projeto foi gentilmente patrocinado pela nearForm.
MIT