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
или более элементов) массивов. Подробнее Создайте функцию stringify()
на основе спецификации jsonschema Draft 7.
Поддерживаемые типы:
'string'
'integer'
'number'
'array'
'object'
'boolean'
'null'
И вложенные тоже.
Пример | Сериализовано как |
---|---|
Date | string через toISOString() |
RegExp | string |
BigInt | integer через toString |
Поддерживаются встроенные форматы дат JSON Schema, которые будут сериализованы как:
Формат | Пример сериализованного формата |
---|---|
date-time | 2020-04-03T09:11:08.615Z |
date | 2020-04-03 |
time | 09:11:08 |
Примечание . В случае даты в строковом формате, а не объекта даты, никаких манипуляций с ней не будет. Он должен быть правильно отформатирован.
Пример с объектом 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"'
Вы можете установить определенные поля объекта в соответствии с требованиями вашей схемы, добавив имя поля внутри required
массива в вашей схеме. Пример:
const schema = {
title : 'Example Schema with required field' ,
type : 'object' ,
properties : {
nickname : {
type : 'string'
} ,
mail : {
type : 'string'
}
} ,
required : [ 'mail' ]
}
Если в объекте, который нужно преобразовать в строку, отсутствуют обязательные поля, 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
поддерживает ключ jsonschema default
для сериализации значения, если оно 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. Дополнительные свойства должны быть объектом или логическим значением, объявленным следующим образом: { type: 'type' }
. Дополнительные свойства будут работать только для тех свойств, которые явно не указаны в объектах свойств и шаблонов .
Если дополнительные свойства отсутствуют или для них установлено значение false
, каждое свойство, которое не указано явно в объектах свойств и шаблонных свойств , будет игнорироваться, как описано в разделе «Отсутствующие поля». Отсутствующие поля игнорируются, чтобы избежать необходимости перезаписывать объекты перед сериализацией. Однако другие правила схемы могут вызывать подобные ситуации. Если для параметра 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
поддерживает ключевые слова AnyOf и oneOf , определенные схемой JSON. Оба должны быть массивом допустимых схем JSON. Различные схемы будут проверены в указанном порядке. Чем больше схем необходимо выполнить stringify
, прежде чем найти совпадение, тем медленнее он будет.
AnyOf и oneOf используют ajv в качестве средства проверки схемы JSON, чтобы найти схему, соответствующую данным. Это влияет на производительность — используйте его только в крайнем случае.
Пример:
const stringify = fastJson ( {
title : 'Example Schema' ,
type : 'object' ,
properties : {
'undecidedType' : {
'anyOf' : [ {
type : 'string'
} , {
type : 'boolean'
} ]
}
}
} )
При указании схем объекта JSON для AnyOf добавьте необходимое ключевое слово проверки, чтобы сопоставлять только объекты с нужными свойствами.
Пример:
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
будет усечено, если указана плавающая точка. Вы можете настроить это поведение с помощью параметра rounding
, который будет принимать round
, ceil
, floor
или trunc
. По умолчанию — 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
В противном случае вместо возникновения ошибки нулевые значения будут принудительно преобразованы следующим образом:
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"}'
Автономный режим используется для компиляции кода, который может быть запущен непосредственно самим 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.
Массачусетский технологический институт