Node.js is an open-source, back-end Javascript runtime environment. It’s popular with developres because they are able to build fast, scalable cross-platform applications. Interviewing Node.js candidates commonly consists of basic and advanced questions to assess technical ability. We sourced these questions from the Node.js community based on developers’ own interview experience and what our clients found important to ask. Could you use help hiring Node.js developers? Scalable Path’s experienced Talent Acquisition team can help.
These are the types of questions typically asked during Node.js interviews. We created them to help you test your understanding of the popular programming language, or guide your initial technical screening with Node.js candidates.
Node.js is a JavaScript runtime. It is an environment that you can use to execute JavaScript outside of the web browser, like inside a server.
Node.js is built on Google’s v8 JavaScript engine, which compiles and executes our source code in a very performant manner. It is one of the primary building blocks of Node.js. Some of the other technologies that make Node.js possible include OpenSSL for providing cryptographic functions or libuv, which handles thread pooling functionality.
In Node.js, all events run on a single thread. If a long-running, synchronous operation is to block that thread, no other operation can be performed until the blocking operation is completed. Blocking is not a problem for short-running operations that can be run asynchronously, like handling HTTP requests. However, long-running, CPU-heavy operations, like Machine Learning related tasks, can be problematic for Node.js since they can consume and block the limited resources available.
Information about function calls gets added to the Call Stack as Stack Frames, and the Event Loop continuously checks the Call Stack to see if there are any functions it needs to run in there.
The message queue is a queue that consists of asynchronous events (like callback functions of setTimeout, fetch responses, etc.) to be processed when the call stack is empty.
Micro Task Queue (also known as Job Queue) is a separate queue used by Promises, which has priority over Message Queue. Once the call stack is empty, the tasks inside the Micro Tasks Queue are executed before the Message Queue is handled.
package.json is a file that records the projects' dependencies alongside the specific versions of those dependencies. We can also use it to record additional metadata about the project, such as the project name, authors, licensing, etc.
In Node.js, you can use function callbacks, Promises, and async/await keywords to handle asynchronous operations.
When working with asynchronous code, it is common to have operations that rely on the resolution of previous operations. When using callbacks, these chains of dependencies can result in a nested structure commonly referred to as callback hell. Using Promises, we can avoid these structures since we have more control over how/when to handle the asynchronous operations.
async/await keywords offer a cleaner alternative to Promise-based asynchronous code since it doesn't require us to use Promise chains. Using async/await keywords, we can write JavaScript code in a synchronous fashion.
Using the async keyword in front of a function name wraps the return value of that function inside a Promise. Using the await keyword before an asynchronous function call suspends the function's execution until it resolves.
Node.js environment provides the building blocks and primitives for developing all kinds of applications. However, the functionality provided by Node.js can be very low-level for advanced use-cases. For this reason, we might want to utilize specialized frameworks that provide high-level primitives, such as using Express for building servers or Electron for building desktop applications.
Transpiling transforms our code from one language to another or a different version of the same language. It allows us to write code using preferential abstractions such as leveraging cutting-edge language features or using Typescript to have data types. The code can then be transpiled into a version of JavaScript that can be compiled and executed.
Preference for streaming over buffering is one of the core design principles of Node.js. Buffering involves pulling everything into the memory and displaying it as such. Streaming is delivering it piece by piece as it becomes available. For example, when reading a file from the disk, you can load the entire file by buffering it before delivering it to the user. Alternatively, you can deliver it continuously in small pieces as it becomes available by streaming it. Buffering large files can take longer and consume a lot of memory, so streaming is preferred over buffering.
Child Processes or Worker Threads can be used to execute CPU-intensive operations outside of the main thread without blocking the primary event loop.
Testing is an integral part of developing maintainable and reliable applications. Some popular testing libraries in Node.js include Mocha, Jest, and Jasmine. There are also complimentary tools like Istanbul for test coverage and Chai for writing rich and expressive assertations. An ideal candidate should have experience with at least one testing library.
Node.js includes some built-in libraries that are part of the core installation. A candidate should have experience with some of these libraries as they are part of the standard workflows in Node.js. This question also assesses the understanding between a built-in library and an external, third-party library. Some commonly used built-in libraries include fs and path for working with the file system, stream for working with streams, and crypto for cryptographic functionalities.
Node.js has some built-in globals that are commonly used when developing Node applications. These include functions like setTimeout, setInterval and objects like console that one might be familiar with from the browser environment. The Node.js specific globals include global and process. There are also pseudo-globals that are included in the module level like __filename and __dirname keywords.
Consistency is essential when developing applications as part of a bigger team. Experience with tools like EditorConfig, Prettier or ESLint ensures that the candidate knows about basic ways of keeping a code style and usage of certain patterns consistent.
Node.js has a vibrant external package/library environment maintained by npm. It is incredibly common for Node.js developers to reach out to npm to introduce features to their applications that they don’t want to develop themselves. Even though installing external dependencies is incredibly convenient, there must be some considerations. Here are some of those considerations that a candidate should have.
Compatibility. You probably shouldn’t use a callback-based library in an application that uses Promises.
Security. Introducing external applications includes security risks. You should prefer packages from well-known maintainers and contributors.
Maintenance. You should prefer actively maintained packages, so there is a chance that they would work on fixing bugs and rolling out security updates.
Performance. Introducing third-party dependencies can introduce performance bottlenecks to your application. You should ensure that these libraries are not deteriorating the performance of your application.
This list isn't exhaustive, and interviewing typically includes an assessment of soft skills and technical ability through a take-home assignment or live coding exercise. You can learn more about hiring here.