As I understand, the libuv thread pool is only used for a few things, one of them being IO that is blocking in nature. This encompasses file system operations (most of the fs
module), which of course includes their async counterparts.
Given that both network I/O and async file I/O are OS-dependent AND non-blocking in nature, why is the former handled by the event loop but the latter handled by the thread pool?
As I understand it, this has to do with the libuv implementation which has not chosen to pursue using OS-native asynchronous file I/O across all the different operating systems that it supports. As such, it uses the thread pool to present an asynchronous interface to the blocking file I/O that is used internal to the thread.
This article discusses some of the possible reasons to avoid OS-level asynchronous file I/O on Windows and could be part of the reason that libuv didn't choose to go that way.
And, this note from Microsoft discusses some of the situations where, even when using a Microsoft asynchronous API, the call ends up being synchronous. In other words, if you want to guarantee that it's always asynchronous, you have to hide it in an OS thread like libuv does.
As for networking interfaces, there is better uniformity of asynchronous support across the various OS platforms that libuv has chosen to rely on.