Non-blocking Asynchronous JSON.parse Using The Fetch API
Update (June 2016)
Right after I published this blog post I received this response from amazing Node.js developer Vladimir Kurchatkin that JSON parsing is not happening in a different thread and in fact it is blocking the main thread. In this tweet I admited I was wrong and I need to update my post.
@j5bot I need to update that post. It's not really in a background thread. It's doing the process in the next tick.https://t.co/5WMeTWb79K
— Mohsen Azimi (@mohsen____) August 4, 2015
Nolan Lawson made following video to demonstrate the effect in multiple browsers:
The problem
I am working on Swagger Editor performance. One of the solutions to speed things up was moving process-intensive task to Web Workers. Web Workers do a great job of moving process-heavy tasks out of the main thread but the way we can communicate with them is very slow. For each message to be sent to or received from a worker we need to convert it to a string. This means for transferring objects between the main thread and worker threads we need to JSON.parse
and JSON.stringify
our objects back and forth.
For larger objects, this can lead to large blocking JSON.parse
calls. For example, when transferring back the AST from our AST-composer worker I saw a 50ms
pause. A 50 millisecond pause can easily drop 4 frames.
The solution
It’s 2015 but JavaScript or the web does not have a non-blocking JSON API! So there is no native or out of the box solution to this. Because communicating with a working is via string, doing JSON.parse
in a worker is also pointless.
When I was exploring the Fetch API (window.fetch
) I noticed the Response
object has an asynchronous .json
method. This is how it’s used:
We can use (abuse?) this API to move all of our JSON-parsing business out of the main thread. It can be done as simple as:
It works as expected:
Performance
Moving JSON.parse
out of the main thread make the actual parsing time less important but let’s see how it’s different than native JSON.parse
:
Result:
The async method is about 2x slower but hey, it’s async and using it blocked the UI for less than a millisecond!
Conclusion
I’ll experiment with this and if it made sense I’ll make a package and publish it. I hope JavaScript or DOM provides native non-blocking JSON APIs so we don’t have to do hacks like this. With async/await
in ES7(ES2016) working with async methods are much easier so we should have async JSON APIs as well.