[{"data":1,"prerenderedAt":1600},["ShallowReactive",2],{"authors":3,"article-2023-06-08-what-makes-fastify-highly-performant-part-1-json-serialization":331},[4,23,35,48,61,73,85,98,111,124,136,148,161,173,185,197,209,221,233,245,258,270,282,295,307,319],{"id":5,"title":6,"body":7,"description":11,"extension":14,"meta":15,"name":16,"navigation":17,"path":18,"readingTime":19,"seo":20,"stem":21,"__hash__":22},"authors\u002Fauthors\u002Falexandre-guillon.md","Software Engineer",{"type":8,"value":9,"toc":10},"minimark",[],{"title":11,"searchDepth":12,"depth":12,"links":13},"",2,[],"md",{},"Alexandre Guillon",true,"\u002Fauthors\u002Falexandre-guillon",1,{"title":6,"description":11},"authors\u002Falexandre-guillon","4tf48mjyjFNqItOHaulICbrjeCyMag1o6801uHeTz98",{"id":24,"title":6,"body":25,"description":11,"extension":14,"meta":29,"name":30,"navigation":17,"path":31,"readingTime":19,"seo":32,"stem":33,"__hash__":34},"authors\u002Fauthors\u002Falexis-ablain.md",{"type":8,"value":26,"toc":27},[],{"title":11,"searchDepth":12,"depth":12,"links":28},[],{},"Alexis Ablain","\u002Fauthors\u002Falexis-ablain",{"title":6,"description":11},"authors\u002Falexis-ablain","_SIAtB7f-39e5t3GiJof81NP47s6MGo2n4gaHkTy1uQ",{"id":36,"title":37,"body":38,"description":11,"extension":14,"meta":42,"name":43,"navigation":17,"path":44,"readingTime":19,"seo":45,"stem":46,"__hash__":47},"authors\u002Fauthors\u002Faxel-shaita.md","Engineering Manager",{"type":8,"value":39,"toc":40},[],{"title":11,"searchDepth":12,"depth":12,"links":41},[],{},"Axel Shaïta","\u002Fauthors\u002Faxel-shaita",{"title":37,"description":11},"authors\u002Faxel-shaita","fK0argUhsBkWLjpTAhY13oYLVzQthcEYkCEdtHWmIgE",{"id":49,"title":50,"body":51,"description":11,"extension":14,"meta":55,"name":56,"navigation":17,"path":57,"readingTime":19,"seo":58,"stem":59,"__hash__":60},"authors\u002Fauthors\u002Fbaptiste-faure.md","Head of Talent Acquisition",{"type":8,"value":52,"toc":53},[],{"title":11,"searchDepth":12,"depth":12,"links":54},[],{},"Baptiste Faure","\u002Fauthors\u002Fbaptiste-faure",{"title":50,"description":11},"authors\u002Fbaptiste-faure","ELisToYtcgHmgdVWZkCclTPV6exZtfyXqhpx1jjbJHs",{"id":62,"title":6,"body":63,"description":11,"extension":14,"meta":67,"name":68,"navigation":17,"path":69,"readingTime":19,"seo":70,"stem":71,"__hash__":72},"authors\u002Fauthors\u002Fbenjamin-bouillot.md",{"type":8,"value":64,"toc":65},[],{"title":11,"searchDepth":12,"depth":12,"links":66},[],{},"Benjamin Bouillot","\u002Fauthors\u002Fbenjamin-bouillot",{"title":6,"description":11},"authors\u002Fbenjamin-bouillot","tbhCFZyfTt7ZM5b5YgqQ2nhgnSTl8BweaQQryc87fHo",{"id":74,"title":37,"body":75,"description":11,"extension":14,"meta":79,"name":80,"navigation":17,"path":81,"readingTime":19,"seo":82,"stem":83,"__hash__":84},"authors\u002Fauthors\u002Fcedric-nicoloso.md",{"type":8,"value":76,"toc":77},[],{"title":11,"searchDepth":12,"depth":12,"links":78},[],{},"Cédric Nicoloso","\u002Fauthors\u002Fcedric-nicoloso",{"title":37,"description":11},"authors\u002Fcedric-nicoloso","ibSoh4VZYiWYTuLOnZTedaAfcnvet1Q9H7ogW0LgorY",{"id":86,"title":87,"body":88,"description":11,"extension":14,"meta":92,"name":93,"navigation":17,"path":94,"readingTime":19,"seo":95,"stem":96,"__hash__":97},"authors\u002Fauthors\u002Fdavid-touzet.md","Staff Engineer",{"type":8,"value":89,"toc":90},[],{"title":11,"searchDepth":12,"depth":12,"links":91},[],{},"David Touzet","\u002Fauthors\u002Fdavid-touzet",{"title":87,"description":11},"authors\u002Fdavid-touzet","dHWwnQxb1Ubt-WwXWEODGEo9AFoq1cJUhfg3kdnYSBM",{"id":99,"title":100,"body":101,"description":11,"extension":14,"meta":105,"name":106,"navigation":17,"path":107,"readingTime":19,"seo":108,"stem":109,"__hash__":110},"authors\u002Fauthors\u002Feloise-chizat.md","Data Engineer",{"type":8,"value":102,"toc":103},[],{"title":11,"searchDepth":12,"depth":12,"links":104},[],{},"Eloïse Chizat","\u002Fauthors\u002Feloise-chizat",{"title":100,"description":11},"authors\u002Feloise-chizat","Utd72Vm9qT4hh2ZbFi6a2_nXw5Wb494Ed_HL1ra5yw8",{"id":112,"title":113,"body":114,"description":11,"extension":14,"meta":118,"name":119,"navigation":17,"path":120,"readingTime":19,"seo":121,"stem":122,"__hash__":123},"authors\u002Fauthors\u002Femmanuel-auclair.md","Staff engineer",{"type":8,"value":115,"toc":116},[],{"title":11,"searchDepth":12,"depth":12,"links":117},[],{},"Emmanuel Auclair","\u002Fauthors\u002Femmanuel-auclair",{"title":113,"description":11},"authors\u002Femmanuel-auclair","MtsA8THNLEn0dTtYEIQaGwDuf7MjQL55IOeei5gugEg",{"id":125,"title":6,"body":126,"description":11,"extension":14,"meta":130,"name":131,"navigation":17,"path":132,"readingTime":19,"seo":133,"stem":134,"__hash__":135},"authors\u002Fauthors\u002Fhoreb-parraud.md",{"type":8,"value":127,"toc":128},[],{"title":11,"searchDepth":12,"depth":12,"links":129},[],{},"Horeb Parraud","\u002Fauthors\u002Fhoreb-parraud",{"title":6,"description":11},"authors\u002Fhoreb-parraud","ajjsnUX4ohZI-ghMdbb92q_taWDkKXVZSLZXoAeLQtg",{"id":137,"title":37,"body":138,"description":11,"extension":14,"meta":142,"name":143,"navigation":17,"path":144,"readingTime":19,"seo":145,"stem":146,"__hash__":147},"authors\u002Fauthors\u002Fhugo-contreras.md",{"type":8,"value":139,"toc":140},[],{"title":11,"searchDepth":12,"depth":12,"links":141},[],{},"Hugo Contreras","\u002Fauthors\u002Fhugo-contreras",{"title":37,"description":11},"authors\u002Fhugo-contreras","2nc3VMu9ASq9Z6Pwx2-7-Ye991Pww4p-UEDBQFfjF-Q",{"id":149,"title":150,"body":151,"description":11,"extension":14,"meta":155,"name":156,"navigation":17,"path":157,"readingTime":19,"seo":158,"stem":159,"__hash__":160},"authors\u002Fauthors\u002Fjulien-tassin.md","Head of Engineering",{"type":8,"value":152,"toc":153},[],{"title":11,"searchDepth":12,"depth":12,"links":154},[],{},"Julien Tassin","\u002Fauthors\u002Fjulien-tassin",{"title":150,"description":11},"authors\u002Fjulien-tassin","iUIHI7SITje38Jh9X9uvYs4-VsHx4eCdt6hAlyLFG_o",{"id":162,"title":6,"body":163,"description":11,"extension":14,"meta":167,"name":168,"navigation":17,"path":169,"readingTime":19,"seo":170,"stem":171,"__hash__":172},"authors\u002Fauthors\u002Flaurent-renard.md",{"type":8,"value":164,"toc":165},[],{"title":11,"searchDepth":12,"depth":12,"links":166},[],{},"Laurent Renard","\u002Fauthors\u002Flaurent-renard",{"title":6,"description":11},"authors\u002Flaurent-renard","5BP7Ed-pt1SQHjh0UJ1XUrlLTcdlFaDoKBCP4deHq8A",{"id":174,"title":6,"body":175,"description":11,"extension":14,"meta":179,"name":180,"navigation":17,"path":181,"readingTime":19,"seo":182,"stem":183,"__hash__":184},"authors\u002Fauthors\u002Fleo-martin.md",{"type":8,"value":176,"toc":177},[],{"title":11,"searchDepth":12,"depth":12,"links":178},[],{},"Léo Martin","\u002Fauthors\u002Fleo-martin",{"title":6,"description":11},"authors\u002Fleo-martin","eYxCHkRgbGDV7shKdTA9s7Tu0zGV4yDGFoKR5MHQntY",{"id":186,"title":6,"body":187,"description":11,"extension":14,"meta":191,"name":192,"navigation":17,"path":193,"readingTime":19,"seo":194,"stem":195,"__hash__":196},"authors\u002Fauthors\u002Floic-bousquet.md",{"type":8,"value":188,"toc":189},[],{"title":11,"searchDepth":12,"depth":12,"links":190},[],{},"Loïc Bousquet","\u002Fauthors\u002Floic-bousquet",{"title":6,"description":11},"authors\u002Floic-bousquet","ko12qZwiGL8XNjAoy9oWypPkIjr29Pbq7vhdtgldqeQ",{"id":198,"title":6,"body":199,"description":11,"extension":14,"meta":203,"name":204,"navigation":17,"path":205,"readingTime":19,"seo":206,"stem":207,"__hash__":208},"authors\u002Fauthors\u002Floic-poullain.md",{"type":8,"value":200,"toc":201},[],{"title":11,"searchDepth":12,"depth":12,"links":202},[],{},"Loïc Poullain","\u002Fauthors\u002Floic-poullain",{"title":6,"description":11},"authors\u002Floic-poullain","oRIyJhFRTqxy5dLCYQ2OnYZ1DB-gLDUM-85vTSYuTF0",{"id":210,"title":100,"body":211,"description":11,"extension":14,"meta":215,"name":216,"navigation":17,"path":217,"readingTime":19,"seo":218,"stem":219,"__hash__":220},"authors\u002Fauthors\u002Fmaud-lelu.md",{"type":8,"value":212,"toc":213},[],{"title":11,"searchDepth":12,"depth":12,"links":214},[],{},"Maud Lélu","\u002Fauthors\u002Fmaud-lelu",{"title":100,"description":11},"authors\u002Fmaud-lelu","MMbsCKuE41OMHusrl12FIEsI-Trx7l8Nn_ANhvj2_y4",{"id":222,"title":37,"body":223,"description":11,"extension":14,"meta":227,"name":228,"navigation":17,"path":229,"readingTime":19,"seo":230,"stem":231,"__hash__":232},"authors\u002Fauthors\u002Fnicolas-poirier.md",{"type":8,"value":224,"toc":225},[],{"title":11,"searchDepth":12,"depth":12,"links":226},[],{},"Nicolas Poirier","\u002Fauthors\u002Fnicolas-poirier",{"title":37,"description":11},"authors\u002Fnicolas-poirier","dXrJkYo8az4SN_D23aYc3fQ7z8s1dR2a0lt1ogjAjJs",{"id":234,"title":37,"body":235,"description":11,"extension":14,"meta":239,"name":240,"navigation":17,"path":241,"readingTime":19,"seo":242,"stem":243,"__hash__":244},"authors\u002Fauthors\u002Fraphael-sauget.md",{"type":8,"value":236,"toc":237},[],{"title":11,"searchDepth":12,"depth":12,"links":238},[],{},"Raphaël Sauget","\u002Fauthors\u002Fraphael-sauget",{"title":37,"description":11},"authors\u002Fraphael-sauget","Uri9bcq0QDuxRA0PbBoNtu7p_5L3dALu4kzcXVW0xyM",{"id":246,"title":247,"body":248,"description":11,"extension":14,"meta":252,"name":253,"navigation":17,"path":254,"readingTime":19,"seo":255,"stem":256,"__hash__":257},"authors\u002Fauthors\u002Fromain-koenig.md","Co-funder & Head of innovation",{"type":8,"value":249,"toc":250},[],{"title":11,"searchDepth":12,"depth":12,"links":251},[],{},"Romain Koenig","\u002Fauthors\u002Fromain-koenig",{"title":247,"description":11},"authors\u002Fromain-koenig","uyS8--eG2_ezyqRABcJnMJmQKKuSArhPWd14aUvFeEw",{"id":259,"title":37,"body":260,"description":11,"extension":14,"meta":264,"name":265,"navigation":17,"path":266,"readingTime":19,"seo":267,"stem":268,"__hash__":269},"authors\u002Fauthors\u002Fromaric-juniet.md",{"type":8,"value":261,"toc":262},[],{"title":11,"searchDepth":12,"depth":12,"links":263},[],{},"Romaric Juniet","\u002Fauthors\u002Fromaric-juniet",{"title":37,"description":11},"authors\u002Fromaric-juniet","4Zb2artgT-eo-PHLXi3xi4d5t7s6PfhUxeSfXIikSUY",{"id":271,"title":6,"body":272,"description":11,"extension":14,"meta":276,"name":277,"navigation":17,"path":278,"readingTime":19,"seo":279,"stem":280,"__hash__":281},"authors\u002Fauthors\u002Fstanyslas-bres.md",{"type":8,"value":273,"toc":274},[],{"title":11,"searchDepth":12,"depth":12,"links":275},[],{},"Stanyslas Bres","\u002Fauthors\u002Fstanyslas-bres",{"title":6,"description":11},"authors\u002Fstanyslas-bres","Xa0SahETuiN4q1jrmR2ych3moAqcZ2LbU7vSfEt2RuU",{"id":283,"title":284,"body":285,"description":11,"extension":14,"meta":289,"name":290,"navigation":17,"path":291,"readingTime":19,"seo":292,"stem":293,"__hash__":294},"authors\u002Fauthors\u002Ftalent-acquisition.md","Talent Acquisition",{"type":8,"value":286,"toc":287},[],{"title":11,"searchDepth":12,"depth":12,"links":288},[],{},"Équipe Talent Acquisition","\u002Fauthors\u002Ftalent-acquisition",{"description":11},"authors\u002Ftalent-acquisition","doDfE76txftQ4wIiKjJoDmSpyzSKk0tzlgVAp6-opAY",{"id":296,"title":6,"body":297,"description":11,"extension":14,"meta":301,"name":302,"navigation":17,"path":303,"readingTime":19,"seo":304,"stem":305,"__hash__":306},"authors\u002Fauthors\u002Fvictor-borg.md",{"type":8,"value":298,"toc":299},[],{"title":11,"searchDepth":12,"depth":12,"links":300},[],{},"Victor Borg","\u002Fauthors\u002Fvictor-borg",{"title":6,"description":11},"authors\u002Fvictor-borg","-Za-JweoiP6hyclue_WkxMXdRUDTczPGlJf6AZckjUc",{"id":308,"title":6,"body":309,"description":11,"extension":14,"meta":313,"name":314,"navigation":17,"path":315,"readingTime":19,"seo":316,"stem":317,"__hash__":318},"authors\u002Fauthors\u002Fvirgil-roger.md",{"type":8,"value":310,"toc":311},[],{"title":11,"searchDepth":12,"depth":12,"links":312},[],{},"Virgil Roger","\u002Fauthors\u002Fvirgil-roger",{"title":6,"description":11},"authors\u002Fvirgil-roger","DfVFe5j0bCgXeEr381ZYOM5DP4m-pWb93J9-m_muKJ0",{"id":320,"title":6,"body":321,"description":11,"extension":14,"meta":325,"name":326,"navigation":17,"path":327,"readingTime":19,"seo":328,"stem":329,"__hash__":330},"authors\u002Fauthors\u002Fyukan-zhao.md",{"type":8,"value":322,"toc":323},[],{"title":11,"searchDepth":12,"depth":12,"links":324},[],{},"Yukan Zhao","\u002Fauthors\u002Fyukan-zhao",{"title":6,"description":11},"authors\u002Fyukan-zhao","LRPHugtAJnWHsmHxy9_SR5Zas_C5p-GR_uHEs1Fhk_E",{"id":332,"title":333,"author":334,"body":335,"date":1590,"description":1591,"extension":14,"lang":1592,"meta":1593,"navigation":17,"path":1594,"published":17,"readingTime":524,"seo":1595,"stem":1596,"tags":1597,"__hash__":1599},"articles\u002Farticles\u002F2023-06-08-what-makes-fastify-highly-performant-part-1-json-serialization.md","What makes Fastify highly performant part 1: JSON serialization","yukan-zhao",{"type":8,"value":336,"toc":1583},[337,349,352,361,367,371,395,399,402,405,467,470,621,636,998,1003,1025,1032,1377,1380,1537,1540,1560,1564,1576,1579],[338,339,340,341,348],"p",{},"At Indy, we use Fastify as the framework for our backend servers. Fastify is a Node.js framework for\ndeveloping web servers. According to its ",[342,343,347],"a",{"href":344,"rel":345},"https:\u002F\u002Fwww.fastify.io\u002Fbenchmarks\u002F",[346],"nofollow","benchmark",", it’s more\nperformant than most of the common Node.js frameworks. Many people may argue that the benchmark is\nnot relevant and it depends on the usage. That might be true but it’s not our topic today. I’m going\nto look into some of the interesting design decisions of the framework that makes it faster. There\nwill be a series of articles and this is the first one that focuses on JSON serialization.",[338,350,351],{},"Since JSON is by far the most dominant format used in HTTP request\u002Fresponse data exchange. JSON\nserialization can have a big impact on the performance of a web server.",[353,354,356,357],"h3",{"id":355},"the-native-function-jsonstringify","The native function: ",[358,359,360],"code",{},"JSON.stringify",[338,362,363,364,366],{},"A native function exists in Javascript to do JSON serialization: ",[358,365,360],{},". But due to the\nnature of Javascript that all variables have dynamic types, it has to do many checks at the runtime\nto determine how to serialize each key of the JSON input according to its type, thus the performance\ncan be hardly optimized.",[353,368,370],{"id":369},"how-did-fastify-do","How did Fastify do",[338,372,373,374,376,377,385,386,388,389,394],{},"So here comes the interesting part: how Fastify achieves a significantly better performance of JSON\nserialization than ",[358,375,360],{},"? The key is to use ",[342,378,381],{"href":379,"rel":380},"https:\u002F\u002Fjson-schema.org\u002F",[346],[382,383,384],"strong",{},"JSON Schema",".\nWe know that a part of the poor performance of ",[358,387,360],{}," is due to the dynamic type checks at\nruntime, so what if we know beforehand the structure of the JSON object (its keys, the type of each\nkey) that we need to serialize? We could easily build a function based on the JSON Schema, and save\nall the time wasted on checking the type of each key at runtime. That’s exactly what\n",[342,390,393],{"href":391,"rel":392},"https:\u002F\u002Fgithub.com\u002Ffastify\u002Ffast-json-stringify",[346],"fast-json-stringify"," does, the internal library\nthat Fastify uses to do JSON serialization. It takes a JSON Schema object as argument and generates\na custom stringify function for future use.",[353,396,398],{"id":397},"dive-into-the-code","Dive into the code",[338,400,401],{},"Let’s do a simple experimentation to see how stringify functions are generated in\nfast-json-stringify.",[338,403,404],{},"Imagine that we want to serialize the following JSON structure:",[406,407,411],"pre",{"className":408,"code":409,"language":410,"meta":11,"style":11},"language-json shiki shiki-themes github-light github-dark","{\n  \"fisrtName\": \"Foo\",\n  \"lastName\": \"Bar\",\n  \"age\": 20\n}\n","json",[358,412,413,421,437,450,461],{"__ignoreMap":11},[414,415,417],"span",{"class":416,"line":19},"line",[414,418,420],{"class":419},"sVt8B","{\n",[414,422,423,427,430,434],{"class":416,"line":12},[414,424,426],{"class":425},"sj4cs","  \"fisrtName\"",[414,428,429],{"class":419},": ",[414,431,433],{"class":432},"sZZnC","\"Foo\"",[414,435,436],{"class":419},",\n",[414,438,440,443,445,448],{"class":416,"line":439},3,[414,441,442],{"class":425},"  \"lastName\"",[414,444,429],{"class":419},[414,446,447],{"class":432},"\"Bar\"",[414,449,436],{"class":419},[414,451,453,456,458],{"class":416,"line":452},4,[414,454,455],{"class":425},"  \"age\"",[414,457,429],{"class":419},[414,459,460],{"class":425},"20\n",[414,462,464],{"class":416,"line":463},5,[414,465,466],{"class":419},"}\n",[338,468,469],{},"First of all, we need a JSON Schema that defines the structure, for example:",[406,471,475],{"className":472,"code":473,"language":474,"meta":11,"style":11},"language-js shiki shiki-themes github-light github-dark","const schema = {\n  title: \"Person schema\",\n  type: \"object\",\n  properties: {\n    firstName: {\n      type: \"string\",\n    },\n    lastName: {\n      type: \"string\",\n    },\n    age: {\n      type: \"integer\",\n      minimum: 0,\n    },\n  },\n  required: [\"firstName\", \"lastName\"],\n};\n","js",[358,476,477,492,502,512,517,522,533,539,545,554,559,565,575,586,591,597,615],{"__ignoreMap":11},[414,478,479,483,486,489],{"class":416,"line":19},[414,480,482],{"class":481},"szBVR","const",[414,484,485],{"class":425}," schema",[414,487,488],{"class":481}," =",[414,490,491],{"class":419}," {\n",[414,493,494,497,500],{"class":416,"line":12},[414,495,496],{"class":419},"  title: ",[414,498,499],{"class":432},"\"Person schema\"",[414,501,436],{"class":419},[414,503,504,507,510],{"class":416,"line":439},[414,505,506],{"class":419},"  type: ",[414,508,509],{"class":432},"\"object\"",[414,511,436],{"class":419},[414,513,514],{"class":416,"line":452},[414,515,516],{"class":419},"  properties: {\n",[414,518,519],{"class":416,"line":463},[414,520,521],{"class":419},"    firstName: {\n",[414,523,525,528,531],{"class":416,"line":524},6,[414,526,527],{"class":419},"      type: ",[414,529,530],{"class":432},"\"string\"",[414,532,436],{"class":419},[414,534,536],{"class":416,"line":535},7,[414,537,538],{"class":419},"    },\n",[414,540,542],{"class":416,"line":541},8,[414,543,544],{"class":419},"    lastName: {\n",[414,546,548,550,552],{"class":416,"line":547},9,[414,549,527],{"class":419},[414,551,530],{"class":432},[414,553,436],{"class":419},[414,555,557],{"class":416,"line":556},10,[414,558,538],{"class":419},[414,560,562],{"class":416,"line":561},11,[414,563,564],{"class":419},"    age: {\n",[414,566,568,570,573],{"class":416,"line":567},12,[414,569,527],{"class":419},[414,571,572],{"class":432},"\"integer\"",[414,574,436],{"class":419},[414,576,578,581,584],{"class":416,"line":577},13,[414,579,580],{"class":419},"      minimum: ",[414,582,583],{"class":425},"0",[414,585,436],{"class":419},[414,587,589],{"class":416,"line":588},14,[414,590,538],{"class":419},[414,592,594],{"class":416,"line":593},15,[414,595,596],{"class":419},"  },\n",[414,598,600,603,606,609,612],{"class":416,"line":599},16,[414,601,602],{"class":419},"  required: [",[414,604,605],{"class":432},"\"firstName\"",[414,607,608],{"class":419},", ",[414,610,611],{"class":432},"\"lastName\"",[414,613,614],{"class":419},"],\n",[414,616,618],{"class":416,"line":617},17,[414,619,620],{"class":419},"};\n",[338,622,623,624,627,628,631,632,635],{},"Next step we should build a function based on the JSON Schema that serializes our JSON object to a\nstring. As we got the JSON schema, we could simply loop over each property and transform the value\nto string according to its type. For example, ",[358,625,626],{},"firstName"," is of type ",[358,629,630],{},"string",", we need to add double\nquotes to its value and the result will be ",[358,633,634],{},"\"firstName\": \"${obj.firstName}\"",".",[406,637,639],{"className":472,"code":638,"language":474,"meta":11,"style":11},"function build(schema) {\n  return function (obj) {\n    let json = \"{\";\n    Object.keys(schema.properties).forEach((key, i, array) => {\n      json += `\"${key}\":`;\n      const type = schema.properties[key].type;\n      switch (type) {\n        case \"string\":\n          json += `\"${obj[key]}\"`;\n          break;\n        case \"integer\":\n          json += \"\" + obj[key];\n          break;\n        default:\n          throw new Error(`${type} unsupported`);\n      }\n      if (i \u003C array.length - 1) {\n        json += \",\";\n      }\n    });\n    json += \"}\";\n    return json;\n  };\n}\n\n\u002F\u002F serialization\nconst customStringify = build(schema);\ncustomStringify(obj);\n",[358,640,641,660,676,693,731,749,762,770,781,805,812,821,836,842,849,874,879,904,917,922,928,941,950,956,961,967,974,989],{"__ignoreMap":11},[414,642,643,646,650,653,657],{"class":416,"line":19},[414,644,645],{"class":481},"function",[414,647,649],{"class":648},"sScJk"," build",[414,651,652],{"class":419},"(",[414,654,656],{"class":655},"s4XuR","schema",[414,658,659],{"class":419},") {\n",[414,661,662,665,668,671,674],{"class":416,"line":12},[414,663,664],{"class":481},"  return",[414,666,667],{"class":481}," function",[414,669,670],{"class":419}," (",[414,672,673],{"class":655},"obj",[414,675,659],{"class":419},[414,677,678,681,684,687,690],{"class":416,"line":439},[414,679,680],{"class":481},"    let",[414,682,683],{"class":419}," json ",[414,685,686],{"class":481},"=",[414,688,689],{"class":432}," \"{\"",[414,691,692],{"class":419},";\n",[414,694,695,698,701,704,707,710,713,715,718,720,723,726,729],{"class":416,"line":452},[414,696,697],{"class":419},"    Object.",[414,699,700],{"class":648},"keys",[414,702,703],{"class":419},"(schema.properties).",[414,705,706],{"class":648},"forEach",[414,708,709],{"class":419},"((",[414,711,712],{"class":655},"key",[414,714,608],{"class":419},[414,716,717],{"class":655},"i",[414,719,608],{"class":419},[414,721,722],{"class":655},"array",[414,724,725],{"class":419},") ",[414,727,728],{"class":481},"=>",[414,730,491],{"class":419},[414,732,733,736,739,742,744,747],{"class":416,"line":463},[414,734,735],{"class":419},"      json ",[414,737,738],{"class":481},"+=",[414,740,741],{"class":432}," `\"${",[414,743,712],{"class":419},[414,745,746],{"class":432},"}\":`",[414,748,692],{"class":419},[414,750,751,754,757,759],{"class":416,"line":524},[414,752,753],{"class":481},"      const",[414,755,756],{"class":425}," type",[414,758,488],{"class":481},[414,760,761],{"class":419}," schema.properties[key].type;\n",[414,763,764,767],{"class":416,"line":535},[414,765,766],{"class":481},"      switch",[414,768,769],{"class":419}," (type) {\n",[414,771,772,775,778],{"class":416,"line":541},[414,773,774],{"class":481},"        case",[414,776,777],{"class":432}," \"string\"",[414,779,780],{"class":419},":\n",[414,782,783,786,788,790,792,795,797,800,803],{"class":416,"line":547},[414,784,785],{"class":419},"          json ",[414,787,738],{"class":481},[414,789,741],{"class":432},[414,791,673],{"class":419},[414,793,794],{"class":432},"[",[414,796,712],{"class":419},[414,798,799],{"class":432},"]",[414,801,802],{"class":432},"}\"`",[414,804,692],{"class":419},[414,806,807,810],{"class":416,"line":556},[414,808,809],{"class":481},"          break",[414,811,692],{"class":419},[414,813,814,816,819],{"class":416,"line":561},[414,815,774],{"class":481},[414,817,818],{"class":432}," \"integer\"",[414,820,780],{"class":419},[414,822,823,825,827,830,833],{"class":416,"line":567},[414,824,785],{"class":419},[414,826,738],{"class":481},[414,828,829],{"class":432}," \"\"",[414,831,832],{"class":481}," +",[414,834,835],{"class":419}," obj[key];\n",[414,837,838,840],{"class":416,"line":577},[414,839,809],{"class":481},[414,841,692],{"class":419},[414,843,844,847],{"class":416,"line":588},[414,845,846],{"class":481},"        default",[414,848,780],{"class":419},[414,850,851,854,857,860,862,865,868,871],{"class":416,"line":593},[414,852,853],{"class":481},"          throw",[414,855,856],{"class":481}," new",[414,858,859],{"class":648}," Error",[414,861,652],{"class":419},[414,863,864],{"class":432},"`${",[414,866,867],{"class":419},"type",[414,869,870],{"class":432},"} unsupported`",[414,872,873],{"class":419},");\n",[414,875,876],{"class":416,"line":599},[414,877,878],{"class":419},"      }\n",[414,880,881,884,887,890,893,896,899,902],{"class":416,"line":617},[414,882,883],{"class":481},"      if",[414,885,886],{"class":419}," (i ",[414,888,889],{"class":481},"\u003C",[414,891,892],{"class":419}," array.",[414,894,895],{"class":425},"length",[414,897,898],{"class":481}," -",[414,900,901],{"class":425}," 1",[414,903,659],{"class":419},[414,905,907,910,912,915],{"class":416,"line":906},18,[414,908,909],{"class":419},"        json ",[414,911,738],{"class":481},[414,913,914],{"class":432}," \",\"",[414,916,692],{"class":419},[414,918,920],{"class":416,"line":919},19,[414,921,878],{"class":419},[414,923,925],{"class":416,"line":924},20,[414,926,927],{"class":419},"    });\n",[414,929,931,934,936,939],{"class":416,"line":930},21,[414,932,933],{"class":419},"    json ",[414,935,738],{"class":481},[414,937,938],{"class":432}," \"}\"",[414,940,692],{"class":419},[414,942,944,947],{"class":416,"line":943},22,[414,945,946],{"class":481},"    return",[414,948,949],{"class":419}," json;\n",[414,951,953],{"class":416,"line":952},23,[414,954,955],{"class":419},"  };\n",[414,957,959],{"class":416,"line":958},24,[414,960,466],{"class":419},[414,962,964],{"class":416,"line":963},25,[414,965,966],{"emptyLinePlaceholder":17},"\n",[414,968,970],{"class":416,"line":969},26,[414,971,973],{"class":972},"sJ8bj","\u002F\u002F serialization\n",[414,975,977,979,982,984,986],{"class":416,"line":976},27,[414,978,482],{"class":481},[414,980,981],{"class":425}," customStringify",[414,983,488],{"class":481},[414,985,649],{"class":648},[414,987,988],{"class":419},"(schema);\n",[414,990,992,995],{"class":416,"line":991},28,[414,993,994],{"class":648},"customStringify",[414,996,997],{"class":419},"(obj);\n",[338,999,1000,1001,635],{},"If we do a benchmark test, it’s over 30% faster than ",[358,1002,360],{},[406,1004,1008],{"className":1005,"code":1006,"language":1007,"meta":11,"style":11},"language-raw shiki shiki-themes github-light github-dark","JSON.stringify x 4,586,512 ops\u002Fsec ±0.42% (99 runs sampled)\ncustom-json-stringify x 6,236,179 ops\u002Fsec ±0.51% (90 runs sampled)\nFastest is custom-json-stringify\n","raw",[358,1009,1010,1015,1020],{"__ignoreMap":11},[414,1011,1012],{"class":416,"line":19},[414,1013,1014],{},"JSON.stringify x 4,586,512 ops\u002Fsec ±0.42% (99 runs sampled)\n",[414,1016,1017],{"class":416,"line":12},[414,1018,1019],{},"custom-json-stringify x 6,236,179 ops\u002Fsec ±0.51% (90 runs sampled)\n",[414,1021,1022],{"class":416,"line":439},[414,1023,1024],{},"Fastest is custom-json-stringify\n",[338,1026,1027,1028,1031],{},"The above function saves some type checking at runtime, but it’s still not optimal. We have to\niterate over each property of the JSON schema and find the right way to serialize its value whenever\nwe call the stringify function. The JSON schema will not change once set, so can we do the iteration\nearlier before calling the stringify function? Actually we need a “generated” function instead of a\nclosure that has access to the JSON schema. There is a way in Javascript to write code dynamically\nand executes it as a function: ",[358,1029,1030],{},"new Function()",". Here is the improved version:",[406,1033,1035],{"className":472,"code":1034,"language":474,"meta":11,"style":11},"function build(schema) {\n  let code = `\n    'use strict'\n    let json = '{'\n  `\n\n  Object.keys(schema.properties).forEach((key, i, array) => {\n        code += `\n      json += '\"${key}\":'\n    `\n\n    const type = schema.properties[key].type\n    switch (type) {\n      case 'string':\n        code += `\n          json += '\"' + obj.${key} + '\"'\n        `\n        break;\n      case 'integer':\n        code += `\n          json += '' + obj.${key}\n        `\n        break;\n      default:\n        throw new Error(`${type} unsupported`)\n    }\n\n    if (i \u003C array.length - 1) {\n      code += 'json += \\\\',\\\\''\n    }\n  })\n\n  code += `\n    json += '}'\n    return json\n  `\n  return new Function('obj', code)\n}\n",[358,1036,1037,1049,1062,1067,1072,1077,1081,1110,1119,1129,1134,1138,1150,1157,1167,1175,1185,1190,1197,1206,1214,1223,1227,1233,1240,1260,1265,1269,1288,1311,1316,1322,1327,1337,1343,1349,1354,1372],{"__ignoreMap":11},[414,1038,1039,1041,1043,1045,1047],{"class":416,"line":19},[414,1040,645],{"class":481},[414,1042,649],{"class":648},[414,1044,652],{"class":419},[414,1046,656],{"class":655},[414,1048,659],{"class":419},[414,1050,1051,1054,1057,1059],{"class":416,"line":12},[414,1052,1053],{"class":481},"  let",[414,1055,1056],{"class":419}," code ",[414,1058,686],{"class":481},[414,1060,1061],{"class":432}," `\n",[414,1063,1064],{"class":416,"line":439},[414,1065,1066],{"class":432},"    'use strict'\n",[414,1068,1069],{"class":416,"line":452},[414,1070,1071],{"class":432},"    let json = '{'\n",[414,1073,1074],{"class":416,"line":463},[414,1075,1076],{"class":432},"  `\n",[414,1078,1079],{"class":416,"line":524},[414,1080,966],{"emptyLinePlaceholder":17},[414,1082,1083,1086,1088,1090,1092,1094,1096,1098,1100,1102,1104,1106,1108],{"class":416,"line":535},[414,1084,1085],{"class":419},"  Object.",[414,1087,700],{"class":648},[414,1089,703],{"class":419},[414,1091,706],{"class":648},[414,1093,709],{"class":419},[414,1095,712],{"class":655},[414,1097,608],{"class":419},[414,1099,717],{"class":655},[414,1101,608],{"class":419},[414,1103,722],{"class":655},[414,1105,725],{"class":419},[414,1107,728],{"class":481},[414,1109,491],{"class":419},[414,1111,1112,1115,1117],{"class":416,"line":541},[414,1113,1114],{"class":419},"        code ",[414,1116,738],{"class":481},[414,1118,1061],{"class":432},[414,1120,1121,1124,1126],{"class":416,"line":547},[414,1122,1123],{"class":432},"      json += '\"${",[414,1125,712],{"class":419},[414,1127,1128],{"class":432},"}\":'\n",[414,1130,1131],{"class":416,"line":556},[414,1132,1133],{"class":432},"    `\n",[414,1135,1136],{"class":416,"line":561},[414,1137,966],{"emptyLinePlaceholder":17},[414,1139,1140,1143,1145,1147],{"class":416,"line":567},[414,1141,1142],{"class":481},"    const",[414,1144,756],{"class":425},[414,1146,488],{"class":481},[414,1148,1149],{"class":419}," schema.properties[key].type\n",[414,1151,1152,1155],{"class":416,"line":577},[414,1153,1154],{"class":481},"    switch",[414,1156,769],{"class":419},[414,1158,1159,1162,1165],{"class":416,"line":588},[414,1160,1161],{"class":481},"      case",[414,1163,1164],{"class":432}," 'string'",[414,1166,780],{"class":419},[414,1168,1169,1171,1173],{"class":416,"line":593},[414,1170,1114],{"class":419},[414,1172,738],{"class":481},[414,1174,1061],{"class":432},[414,1176,1177,1180,1182],{"class":416,"line":599},[414,1178,1179],{"class":432},"          json += '\"' + obj.${",[414,1181,712],{"class":419},[414,1183,1184],{"class":432},"} + '\"'\n",[414,1186,1187],{"class":416,"line":617},[414,1188,1189],{"class":432},"        `\n",[414,1191,1192,1195],{"class":416,"line":906},[414,1193,1194],{"class":481},"        break",[414,1196,692],{"class":419},[414,1198,1199,1201,1204],{"class":416,"line":919},[414,1200,1161],{"class":481},[414,1202,1203],{"class":432}," 'integer'",[414,1205,780],{"class":419},[414,1207,1208,1210,1212],{"class":416,"line":924},[414,1209,1114],{"class":419},[414,1211,738],{"class":481},[414,1213,1061],{"class":432},[414,1215,1216,1219,1221],{"class":416,"line":930},[414,1217,1218],{"class":432},"          json += '' + obj.${",[414,1220,712],{"class":419},[414,1222,466],{"class":432},[414,1224,1225],{"class":416,"line":943},[414,1226,1189],{"class":432},[414,1228,1229,1231],{"class":416,"line":952},[414,1230,1194],{"class":481},[414,1232,692],{"class":419},[414,1234,1235,1238],{"class":416,"line":958},[414,1236,1237],{"class":481},"      default",[414,1239,780],{"class":419},[414,1241,1242,1245,1247,1249,1251,1253,1255,1257],{"class":416,"line":963},[414,1243,1244],{"class":481},"        throw",[414,1246,856],{"class":481},[414,1248,859],{"class":648},[414,1250,652],{"class":419},[414,1252,864],{"class":432},[414,1254,867],{"class":419},[414,1256,870],{"class":432},[414,1258,1259],{"class":419},")\n",[414,1261,1262],{"class":416,"line":969},[414,1263,1264],{"class":419},"    }\n",[414,1266,1267],{"class":416,"line":976},[414,1268,966],{"emptyLinePlaceholder":17},[414,1270,1271,1274,1276,1278,1280,1282,1284,1286],{"class":416,"line":991},[414,1272,1273],{"class":481},"    if",[414,1275,886],{"class":419},[414,1277,889],{"class":481},[414,1279,892],{"class":419},[414,1281,895],{"class":425},[414,1283,898],{"class":481},[414,1285,901],{"class":425},[414,1287,659],{"class":419},[414,1289,1291,1294,1296,1299,1302,1305,1308],{"class":416,"line":1290},29,[414,1292,1293],{"class":419},"      code ",[414,1295,738],{"class":481},[414,1297,1298],{"class":432}," 'json += ",[414,1300,1301],{"class":425},"\\\\",[414,1303,1304],{"class":432},"'",[414,1306,1307],{"class":419},",\\\\",[414,1309,1310],{"class":432},"''\n",[414,1312,1314],{"class":416,"line":1313},30,[414,1315,1264],{"class":419},[414,1317,1319],{"class":416,"line":1318},31,[414,1320,1321],{"class":419},"  })\n",[414,1323,1325],{"class":416,"line":1324},32,[414,1326,966],{"emptyLinePlaceholder":17},[414,1328,1330,1333,1335],{"class":416,"line":1329},33,[414,1331,1332],{"class":419},"  code ",[414,1334,738],{"class":481},[414,1336,1061],{"class":432},[414,1338,1340],{"class":416,"line":1339},34,[414,1341,1342],{"class":432},"    json += '}'\n",[414,1344,1346],{"class":416,"line":1345},35,[414,1347,1348],{"class":432},"    return json\n",[414,1350,1352],{"class":416,"line":1351},36,[414,1353,1076],{"class":432},[414,1355,1357,1359,1361,1364,1366,1369],{"class":416,"line":1356},37,[414,1358,664],{"class":481},[414,1360,856],{"class":481},[414,1362,1363],{"class":648}," Function",[414,1365,652],{"class":419},[414,1367,1368],{"class":432},"'obj'",[414,1370,1371],{"class":419},", code)\n",[414,1373,1375],{"class":416,"line":1374},38,[414,1376,466],{"class":419},[338,1378,1379],{},"The generated function looks like this:",[406,1381,1383],{"className":472,"code":1382,"language":474,"meta":11,"style":11},"function stringify(obj) {\n  let json = \"{\";\n  json += '\"firstName\":';\n  json += '\"' + obj.firstName + '\"';\n  json += \",\";\n  json += '\"lastName\":';\n  json += '\"' + obj.lastName + '\"';\n  json += \",\";\n  json += '\"age\":';\n  json += \"\" + obj.age;\n  json += \"}\";\n  return json;\n}\n",[358,1384,1385,1398,1410,1422,1443,1453,1464,1483,1493,1504,1517,1527,1533],{"__ignoreMap":11},[414,1386,1387,1389,1392,1394,1396],{"class":416,"line":19},[414,1388,645],{"class":481},[414,1390,1391],{"class":648}," stringify",[414,1393,652],{"class":419},[414,1395,673],{"class":655},[414,1397,659],{"class":419},[414,1399,1400,1402,1404,1406,1408],{"class":416,"line":12},[414,1401,1053],{"class":481},[414,1403,683],{"class":419},[414,1405,686],{"class":481},[414,1407,689],{"class":432},[414,1409,692],{"class":419},[414,1411,1412,1415,1417,1420],{"class":416,"line":439},[414,1413,1414],{"class":419},"  json ",[414,1416,738],{"class":481},[414,1418,1419],{"class":432}," '\"firstName\":'",[414,1421,692],{"class":419},[414,1423,1424,1426,1428,1431,1433,1436,1439,1441],{"class":416,"line":452},[414,1425,1414],{"class":419},[414,1427,738],{"class":481},[414,1429,1430],{"class":432}," '\"'",[414,1432,832],{"class":481},[414,1434,1435],{"class":419}," obj.firstName ",[414,1437,1438],{"class":481},"+",[414,1440,1430],{"class":432},[414,1442,692],{"class":419},[414,1444,1445,1447,1449,1451],{"class":416,"line":463},[414,1446,1414],{"class":419},[414,1448,738],{"class":481},[414,1450,914],{"class":432},[414,1452,692],{"class":419},[414,1454,1455,1457,1459,1462],{"class":416,"line":524},[414,1456,1414],{"class":419},[414,1458,738],{"class":481},[414,1460,1461],{"class":432}," '\"lastName\":'",[414,1463,692],{"class":419},[414,1465,1466,1468,1470,1472,1474,1477,1479,1481],{"class":416,"line":535},[414,1467,1414],{"class":419},[414,1469,738],{"class":481},[414,1471,1430],{"class":432},[414,1473,832],{"class":481},[414,1475,1476],{"class":419}," obj.lastName ",[414,1478,1438],{"class":481},[414,1480,1430],{"class":432},[414,1482,692],{"class":419},[414,1484,1485,1487,1489,1491],{"class":416,"line":541},[414,1486,1414],{"class":419},[414,1488,738],{"class":481},[414,1490,914],{"class":432},[414,1492,692],{"class":419},[414,1494,1495,1497,1499,1502],{"class":416,"line":547},[414,1496,1414],{"class":419},[414,1498,738],{"class":481},[414,1500,1501],{"class":432}," '\"age\":'",[414,1503,692],{"class":419},[414,1505,1506,1508,1510,1512,1514],{"class":416,"line":556},[414,1507,1414],{"class":419},[414,1509,738],{"class":481},[414,1511,829],{"class":432},[414,1513,832],{"class":481},[414,1515,1516],{"class":419}," obj.age;\n",[414,1518,1519,1521,1523,1525],{"class":416,"line":561},[414,1520,1414],{"class":419},[414,1522,738],{"class":481},[414,1524,938],{"class":432},[414,1526,692],{"class":419},[414,1528,1529,1531],{"class":416,"line":567},[414,1530,664],{"class":481},[414,1532,949],{"class":419},[414,1534,1535],{"class":416,"line":577},[414,1536,466],{"class":419},[338,1538,1539],{},"In the end, it’s just some string concatenation when we call the stringify function. The benchmark\nshows that the performance is significantly boosted.",[406,1541,1543],{"className":1005,"code":1542,"language":1007,"meta":11,"style":11},"JSON.stringify x 4,653,809 ops\u002Fsec ±0.28% (97 runs sampled)\nfast-json-stringify x 1,032,584,240 ops\u002Fsec ±0.23% (100 runs sampled)\nFastest is fast-json-stringify\n\n",[358,1544,1545,1550,1555],{"__ignoreMap":11},[414,1546,1547],{"class":416,"line":19},[414,1548,1549],{},"JSON.stringify x 4,653,809 ops\u002Fsec ±0.28% (97 runs sampled)\n",[414,1551,1552],{"class":416,"line":12},[414,1553,1554],{},"fast-json-stringify x 1,032,584,240 ops\u002Fsec ±0.23% (100 runs sampled)\n",[414,1556,1557],{"class":416,"line":439},[414,1558,1559],{},"Fastest is fast-json-stringify\n",[353,1561,1563],{"id":1562},"conclusion","Conclusion",[338,1565,1566,1567,1572,1573,1575],{},"The above code is from the\n",[342,1568,1571],{"href":1569,"rel":1570},"https:\u002F\u002Fgithub.com\u002Ffastify\u002Ffast-json-stringify\u002Fcommit\u002Fa7873f04f3156eafaf4beb5dcf85596cd6f53648",[346],"first commit","\nof fast-json-stringify. Of course the actual library is more complex than that. For example it needs\nto validate the input to make sure that it has the correct structure, it should deal with circular\nJSON reference, it also has to sanitize the JSON Schema for security concerns as we can see from\nabove that it uses ",[358,1574,1030],{}," internally, and maybe we should never pass an unknown or\nuser-generated schema to it.",[338,1577,1578],{},"The idea behind it is a really simple but yet great and clever one which essentially moves the\nruntime analysis to “compile time” to achieve performance boost.",[1580,1581,1582],"style",{},"html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sScJk, html code.shiki .sScJk{--shiki-default:#6F42C1;--shiki-dark:#B392F0}html pre.shiki code .s4XuR, html code.shiki .s4XuR{--shiki-default:#E36209;--shiki-dark:#FFAB70}html pre.shiki code .sJ8bj, html code.shiki .sJ8bj{--shiki-default:#6A737D;--shiki-dark:#6A737D}",{"title":11,"searchDepth":12,"depth":12,"links":1584},[1585,1587,1588,1589],{"id":355,"depth":439,"text":1586},"The native function: JSON.stringify",{"id":369,"depth":439,"text":370},{"id":397,"depth":439,"text":398},{"id":1562,"depth":439,"text":1563},"2023-06-08","Since JSON is by far the most dominant format used in HTTP request\u002Fresponse data exchange. JSON serialization can have a big impact on the performance of a web server.","en",{},"\u002Farticles\u002F2023-06-08-what-makes-fastify-highly-performant-part-1-json-serialization",{"title":333,"description":1591},"articles\u002F2023-06-08-what-makes-fastify-highly-performant-part-1-json-serialization",[1598],"Tech","F-wCN6rB8-L0JfRjkOVCo6ftDNazVhvDefcOLS7K0tw",1775837023388]