-
Notifications
You must be signed in to change notification settings
Consider switching to the Jawn parser on JS #1941
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Comments
I'm in favor of switching to Jawn as the default parser on 0.15.x. |
There's an argument to make this change in the 0.14.x line as a bug fix. |
This does feel like the right move, but there are areas where performance of I'm in favor of switching in principle, but wonder what we can do to bring the jawn more in parity in these cases before switching. I want to try avoiding as best I can anybody coming out to complain about a sudden performance change they didn't opt into 😅 . |
@zarthross thanks for taking a look into this!
Genuine question: do you have some specific users in mind? The reason I ask is, although I 100% agree that in some of these microbenchmarks Jawn definitely leaves something to be desired, it also makes improvements in a number of areas. For example Big picture, looking at API responses (rather than microbenchmarks of very specific things) Jawn seems to be more performant than
Fair :) I mean, every change has the possibility to upset somebody 😆 the nice thing about this change, is that anyone who is unhappy can just swap to |
@zarthross we could write a parser which uses Jawn for some cases and |
@armanbilge I think its the right move for 0.15. I'll think about it for 0.14.x and talk with @zmccoy. I wish we had some benchmarks for nodejs as well to compare and make sure that meshes with what we are seeing with browsers. As for your question about specific users, no... I don't know any specific user which would have an issue. @isomarcte It would be better if we could do some WASM magic or something to hyperoptimize our js json parser 😆 |
Thanks.
I'll see if I can look into this. Note that Chrome and Node.js both use the same V8 Javascript runtime, so I would expect the Chrome results to be representative for Node.js. |
Done in #2042. |
tl;dr The circe-jawn parser on JS has better semantics and in many cases out-performs the
JSON.parse
method currently used by circe-parser.Benchmarks: https://armanbilge.github.io/jsoniter-scala/index-scalajs.html
Note that the above benchmark results were extracted from https://plokhotnyuk.github.io/jsoniter-scala/index-scalajs.html; all credit goes to @plokhotnyuk.
In #1791, the circe-jawn module was cross-built for JS. However, the circe-parser module continued to use the standard JS API
JSON.parse
for parsing and this was "unlikely to change" according to typelevel/jawn#351 (comment). Presumably this was for performance-related reasons:JSON.parse
is provided by the runtime, so no parsing code has to be bundled in applications' size-sensitive JS artifacts.JSON.parse
with highly-optimized native code, so it should be fast.However, as noted in the circe docs, the use of
JSON.parse
also has some serious caveats:circe/docs/src/main/tut/parsing.md
Lines 61 to 69 in a015255
This (often surprising) difference in semantics can cause problems such as #393 and #1911 (comment) and has "raised eyebrows".
@sjrd in https://discord.com/channels/632150470000902164/635668814956068864/905900410517204992
Note that the circe-jawn.js parser does not have these issues and instead has semantics that match the JVM, since it is parsing from
String
to theJson
AST with exactly the same code.With much gratitude to @plokhotnyuk who maintains comprehensive browser benchmarks for Scala.js JSON libraries, we now have concrete numbers comparing circe-jawn.js to circe-parser.js. I've trimmed down @plokhotnyuk's webpage to just the relevant benchmarks for this comparison. For easiest viewing I recommend selecting a specific browser to focus on.
https://armanbilge.github.io/jsoniter-scala/index-scalajs.html
It's also possible to run the benchmarks yourself at:
https://plokhotnyuk.github.io/jsoniter-scala/scala-2.13-fullopt.html
Here's my rough summary/analysis from looking through the Chrome results, but please draw your own conclusions :)
JSON.parse
JSON.parse
when parsing API responses (GH, Twitter, Google Maps)JSON.parse
JSON.parse
may return incorrect results, so it's not really a fair comparisonBesides raw performance, I had previously investigated how circe-jawn affects the size of the JS artifact. In http4s/http4s-dom#10 (comment) I estimated it contributes roughly 15 KB (fullOptJS+gcc, pre-gzip). I don't think this is a big deal, and definitely not in the Typelevel-stack Scala.js apps I've seen 😆
In summary, I think the circe-parser module should switch to use the Jawn parser on JS (although maybe not until the next breaking release). This gets us:
Of course, the
JSON.parse
-based parser should continue to be provided in thecirce-scalajs
module. Users who are specifically concerned about artifact size and/or performance of numerics parsing and willing to accept the shortcomings ofJSON.parse
, can use this parser instead.Thanks for reading :)
The text was updated successfully, but these errors were encountered: