Understanding NodeJS' fs.mkdtemp()

Despite having used Node.js a lot in the past few years, I've never actually dug deep into the fs library. I've never really needed to dig deep into the fs library -- my Node.js projects have largely been RESTful servers, which pulled JSON objects from a document database (mongoDB, usually). So when I was told to go research a function from the fs library, I was actually a little excited. ...And slightly apprehensive. I haven't had much experience reading code, so I knew finding the information I needed could be a bit tricky. Fortunately, Node.js has some of the most well-organized documentation I've ever seen, so beyond finding a few obscure files, I didn't have too tough a time. So, without further ado, let's get to looking at the function I chose to learn about: fs.mkdtemp().

What is fs.mkdtemp()?

fs.mkdtemp() is a function in NodeJS' fs library. According to the official docs, it "creates a unique, temporary directory." Honestly, at first glance, I didn't really understand why this was useful -- I don't have much experience in dealing with file systems, so I turned to Google for answers. One StackExchange discussion seemed to have the answers I was looking for. I don't think I could do those explanations justice, so I won't bother breaking it down -- go check out that post I linked if you want to learn more.

Examining the Source Code

One of the best ways to truly understand a function is to examine the source code. I pulled this from the Node.js Github, and you can find the exact chunk of code here.

function mkdtemp(prefix, options, callback) { callback = makeCallback(typeof options === 'function' ? options : callback); options = getOptions(options, {}); if (!prefix || typeof prefix !== 'string') { throw new ERR_INVALID_ARG_TYPE('prefix', 'string', prefix); } nullCheck(prefix, 'prefix'); const req = new FSReqCallback(); req.oncomplete = callback; binding.mkdtemp(`${prefix}XXXXXX`, options.encoding, req); }
So, it's a pretty short function, from what we can see. Let's start by breaking down the parameters:
  • Prefix: A string, used as the name of the temporary directory. A series of random characters will be appended to the prefix to ensure that the directory is unique -- so if your prefix is tempDir, mkdtemp() will make a directory named tempDirabc123, for example.
  • Options: Options is optional. It can be a string or an object that denotes what type of encoding to use. The default is UTF8.
  • Callback: mkdtemp() is asynchronous, so the callback is code you want executed once the function has finished. It has two parameters: err (an error), and the folder that mkdtemp() created. There is a synchronous version of this function called mkdtempSync(), which instead returns the newly created folder.
Now that we know what the parameters mean, we can move ahead with looking at the rest of the code. The first two lines call two different functions: makeCallback() and getOptions(), the results of which get stored in callback and options, respectively. I won't be looking in-depth at either function, but just from the names and what the returns are stored in, it's pretty evident that makeCallback will create the callback function, while getOptions retrieves options--in this case, that means the kind of encoding to be used.

After that, mkdtemp() makes sure that the prefix entered is valid -- if the prefix doesn't exist or isn't a string, the function will throw an error and cease operations. If the prefix does exist and is a string, mkdtemp() then calls nullCheck() on it. nullCheck() is a function from the internal/fs/utils.js file that checks for null types in a path that is of type string or Uint8Array. If there are null types, it will throw an error; if there aren't null types, it quietly returns this information and mkdtemp() continues on to the next line, where it creates a new instance of FSReqCallback.

From what I can tell, FSReqCallback behaves like a sort of watcher; it monitors the progress of mkdtemp() and when everything is finished, it will call the previously defined callback. From there, we use binding to allow Node.js to actually create the directory on our machine. Binding does this by "connecting" two different languages, so to speak; being written in JavaScript, Node.js can't modify our machines directly -- it has to bind to a library written in a language the OS can understand and execute.

And that's that! If you want to learn more about mkdtemp(), or any other Node.js function, I recommend checking out the project on GitHub and going through the documentation. There's a lot of great information there, and I am very much looking forward to going through some of it in my own time.