Mohan pd.
Mohan pd. Author of The Coders Blog. Also a professional fullstack javascript developer working with various tech company and client around world.

All You Need to Know About NodeJS

Sep 22, 2019 · 16 minutes
All You Need to Know About NodeJS

1. What is Node & where can we use it?

Node is a server side scripting language based on Google’s V8 JavaScript engine. It is used to build scalable programs that are computationally simple but frequently accessed.

You can use node in I/O intensive web applications like video streaming site, real-time web applications, network applications, general-purpose applications, and distributed systems.

2. Why use Node?

Node makes build scalable network programs easy. Advantages include:

  • it is generally fast
  • it almost never blocks
  • offers unified programming language(javascript) and data type(json)
  • everything is asynchronous
  • yields great concurrency

3. What are the features of Node?

  • Node is single-threaded but highly scalable
  • uses async, event-driven I/O instead of separate processes or threads
  • able to achieve high output via single-threaded event loop and non-blockin I/O

4. What is the output and how else can the code below be writting in Node to produce the same output?

Input

console.log('first');
setTimeout(function() {
  console.log('second');
}, 0);
console.log('third');

Log

first
third
second

Node Input

console.log('first');
setImmediately(function() {
  console.log('second');
}, 0);
console.log('third');

setImmediately(fn) will be used in palce of setTimeout(fn, 0) since it is faster

5. Why is Node single-threaded?

Node is single threaded for async processing. By doing async processing on a single-thread under typical web loads, more performance and scalability can be achieved. single thread provide more gains than thread-based implementation.

6. Explain callbacks in Node.

A callback function is called at the completion of a task. This allows other code to be run in the meantime and prevents blocking. Being async, Node heavily relies on callbacks.

7. How do you prevent/fix callback hell?

  • handle every single error
  • keep your code shallow
  • modularize - split the callbacks into smaller, independent functions that can be called with some parameters then joining them

8. Explain the role of REPL in Node.

REPL performs read, eval, print, and loop tasks. REPL is used to execute ad-hoc javascript statements. The REPL shell allows entry to javascript and evaluates the results. REPL is criticle for the purpose of testing, debugging, and experimenting.

9. Name the types of API functions in Node.

  • blocking functions: in a blocking operation, all other code is blocked form executing until an I/O event that is waited on occurs. Executes synchronously.
  • non-blocking functions: multiple I/O calls can be performed without the execution of the program being halted.

10. What are “streams” in Node? Explain the different types of streams present in Node.

Streams are objects that allow reading of data from the source and writing of data to the destination as a continuous process

There are four types:

  • read opeartion
  • write operation
  • read and write operations
  • Duplex stream that performs computations based on the available input

11. What are exit codes in Node?

  • unused
  • uncaught fatal exception
  • fatal error
  • non-function internal exception handler
  • internal exception handler run-time failure
  • internal javascript evaluation failure

12. what are globals in Node?

  • global: represents the global namespace and acts as a container for all other objects
  • process: one of the global objects but can turn a synchronous function into an async callback. It can be accessed from anywhere in the code and it primarily gives back information about the application or the environment
  • buffer: is a class in Node to handle binary data

13. How does Node handle child threads?

It does not expose child threads and thread management methods to the developer. Technically, Node does spawn child threads for certain tasks such as async I/O, but these run behind the scenes and do not execute any application JavaScript code, nor block the main event loop.

If threading support is desired in a Node application, there are tools available to enable it, such as ChildProcess module.

14. What is the preferred method of resolving unhandled exceptions in Node?

Unhandled exceptions in Node can be caught at the Process level by attaching a handler for uncaughtException event.

process.on('uncaughtException', function(err) {
	console.log('Caught exception:', err);
});

However, uncaughtException is a very crude mechanism for exception handling and may be removed from Node.js in the future.

If an exception has bubbled up all the way to the Process level, your application may be in an undefined state and would need to restart.

The preferred way is to add another layber between your application and the Node process which is called the domain.

Domains provide a way to handle multiple different I/O operations as a single group. So, by having your application, or part of it, running in a separate domain, you can safely handle exceptions at the domain level, before they reach the Process level.

15. How does Node support multi-processor platforms, and does it fully utilize all processor resources?

Since Node is by default a single-threaded application, it will run on a single processor core and will not take full advantage of multicore processors.

However, Node provides support for deployment on multi-core systems, to take greater advantage of the hardware.

The Cluster module is one of the core Node modules and it allows running multiple Node worker processes that will share the same port.

16. Consider the following:

console.time("loop");
for (var i = 0; i < 1000000; i += 1){
    // Do nothing
}
console.timeEnd("loop");

The time required to run this code in Google Chrome is considerably more than the time required to run it in Node. Explain why this is so, even though both use the v8 JavaScript Engine.

  • within a web browser, declaring i outisde of a function’s scope makes it global and therefore binds to the window
  • as a result, running this requires the browser to repeatedly resolve i in a heavily populated window namespace
  • declaring any variable outside of any function’s scope bindes it only to the module’s own scope(not on the window), therefore faster to resolve

17. What are the two arguments that async.queue takes?

Task function and concurrency value

18. Mention the steps by which you can async in Node.

  • first class functions
  • function composition
  • callback counters
  • event loops

18. What’s a stub? Name a use case.

Stubs are functions/programs that simulate the behaviors of components/modules. Stubs provide canned answers to function calls made during test cases.

var fs = require('fs');

var writeFileStub = sinon.stub(fs, 'writeFile', function (path, data, cb) {
  return cb(null);
});

expect(writeFileStub).to.be.called;
writeFileStub.restore();

19. What’s a test pyramid?

A test pyramid describes the ratio of how many unit tests, integration tests and end-to-end test you should write.

An example for an HTTP API may look like this:

  • lots of low-level unit tests for models (dependencies are stubbed)
  • fewer integration tests, where you check how your models interact with each other (dependencies are not stubbed)
  • less end-to-end tests, where you call your actual endpoints (dependencies are not stubbed)

20. What’s your favorite HTTP framework and why?

There is no right answer for this. The goal here is to understand how deeply one knows the framework she/he uses. Tell what are the pros and cons of picking that framework.

21. When are background/worker processes useful? How can you handle worker tasks?

Worker processes are extremely useful if you’d like to do data processing in the background, like sending out emails or processing images.

There are lots of options for this like RabbitMQ or Kafka.

22. How can you secure your HTTP cookies against XSS attacks?

XSS occurs when the attacker injects executable JavaScript code into the HTML response.

To mitigate these attacks, you have to set flags on the set-cookie HTTP header:

  • HttpOnly - this attribute is used to help prevent attacks such as cross-site scripting since it does not allow the cookie to be accessed via JavaScript.
  • secure - this attribute tells the browser to only send the cookie if the request is being sent over HTTPS.

23. How can you make sure your dependencies are safe?

When writing Node.js applications, ending up with hundreds or even thousands of dependencies can easily happen. For example, if you depend on Express, you depend on 27 other modules directly, and of course on those dependencies’ as well, so manually checking all of them is not an option!

The only option is to automate the update / security audit of your dependencies. For that there are free and paid options:

  • npm outdated
  • Trace by RisingStack
  • NSP
  • GreenKeeper
  • Snyk

24. What is the event loop? Is it part of V8?

The event loop is in libuv and not part of V8.

your code your code your code
V8 core modules core modules
V8 C++ Bindings C++ Bindings
V8 libuv c-ares, http, …
the OS the OS the OS

The event loop…

  • the entity that handles external events and converts them to callback invocations
  • a loop that picks events from the event queue and pushes their callback to the callstack
  • decides what goes where.. lives between V8(heap/stack) and queue

25. What will Node do when both the callstack and the event loop queue are empty?

If there is nothing to do, Node will exit - process.exit().

26. Besides V8 and libuv, what other external dependencies does Node have?

  • http-parser
  • c-ares
  • OpenSSL
  • zlib

They have their own source code and license.

27. Can Node work without V8?

Yes it can, with Chakra!

28. Why are module.exports, exports.g, and module.exports.g OKAY, but not exports?

Because ‘exports’ is just a reference(alias) to ‘module.exports’, and when you change exports, you change that reference and you are no longer changing the API. You are changing some local variable.

Every node file gets its own IIFE behind the scenes. Node wraps your code in a function. console.log(arguments) will give you arguments when ran with Node

29. The objects: exports, require, and module are globally available in every file but they are different in every file. How?

Because of that magic IIFE…

> require('module').wrapper
[ '(function (exports, require, module, __filename, __dirname) {
// ...
});' ]

30. What are the 5 major steps that require function does?

  1. attempt to resolve what you are attempting to require. it will try to map that string that you required into an actual path on the file system this path could be local to your node, node_modules, parent node_modules, etc..
  2. loads content of that file after it resolves it into memory
  3. wraps the content with that magic IIFE
  4. evaluates the file, probably with V8
  5. cache - the next time you require the exact same file, the last steps will not need to happen. Node will just read it from the cache

31. How do you check for the existence of a local module?

Using require.resolve('module-name') will check to see if a module exists and throws and error that you can catch.

32. What are circular modular dependencies in Node?

Node allows this and you will NOT get an error. The only problem is that when one module is still loading, the other module will get a partial version of that loading module.

module1: require('module2');
module2: require('module1');

33. What are the 3 file extensions that will be automatically tried by the require function?

It will try .js, then, .json, then .node.

  • If you have a .json file, you just require it directly, and Node will automatically parse it and put it in a JavaScript object for you
  • A .node file is a binary file. So if you have some C code, you can just compile the C code into a .node file using some node package and you can just require the C code directly. You don’t have to require the JavaScript

34. What are the major differences between spawn and exec?

Node can tell the OS to run a command and the OS will give Node back some output. But spawn and exec both allow you to do that.

Differences and significance:

spawn exec
no shell (security risk) uses shell
streams (for large data) buffer output

What is spawn(), execFile(), fork(), exec()?

Tell Me More!

35. How can we make Node always use JavaScript strict mode?

The argumen is interesting because it is a V8 argument. Node relays that to V8 and V8 will start in strict mode.

$ node --use-strict
> a = 1
ReferenceError: a is not defined

36. What is process.argv ? What type of data does it hold?

When you specify arguments to the node command those arguments get captured in an array and all the argument values are captured as strings.

$ node -p process.argv 42 hello world
> [ '/usr/local/kev/node/8.9.6/bin/node', '42', 'hello', 'world' ]

37. How can we do one final operation before a Node process crashes? Can that operation be done asynchoronously?

Yes! uncaughtException is a generic error - “I’m crashing, what do you want me to do?”.

This operation cannot be done async because at this point, the event loop just gave up. Its not working anymore!

process.on('uncaughtException', (err) => {
fs.writeSync(1, `Caught exception: ${err}\n`);
process.exit(1); // not optional, let process exit!
});

Terrible mistake happend, let Node restart.

38. What are the built-in dot commands that you can use in Node’s REPL?

Run .help in the terminal.

39. What does the _ mean inside of Node’s REPL?

Gets last executed value and captures that in the underscore variable.

$ node
>
> Math.random()
0.345234523452345
>
> const a = _
>
> a
0.345234523452345
>

40. What is the difference between Buffer.alloc and Buffer.allocUnsafe

Buffer.alloc gives you a chunk of the memory and actually resets that chunk for you with zeros

Buffer.allocUnsafe just gives you a chunk of the memory and you can read what’s already in that memory, so you can actually leak information. It us faster than Buffer.alloc

41. How does the cluster module work?

The cluster module helps with scalabilty, particularly with cloning. Good for scaling one server on multiple cores. Very simple process.

But… the workers have their own memory, V8, callstack. No longer share things in memory, no longer cache things in memory. If you want to cache, you gotta build another entity with its own API and have all the workers can work with that entity.

PM2 uses cluster module by default. If using PM2 on a multicore processor and caching, you’re prob doing it wrong. Some workers will not be aware of other worker’s memory.

Scaling Node Applications

42. When is it okay to use the file system *Sync methods?

Depends on the situation. Ex: if you initializing the server, sync is okay because it’s a one time thing and everything else is depending on all of it to be loaded.

43. How can you print only one level of a deeply nested object?

> console.dir(global, { depth: 0 })

44. How can you debug a Node program in Chrome dev-tools?

You can’t! Instead use node --inspect. Node will give you a link that you can go to and it’ll be as if you’re using Chrome dev-tools

45. Asynchrony

Callback !== Asynchrony

You want your functions to always be synchronous or always async

46. What is the difference between using event emitters and using callback functions for async handling of code?

event emitter: objects that you can extend and build in custom logic. event emits can just omit those dynamic strings - any string - and you can register handlers to be invoked when those strings get emitted.

callbacks: are like a special form of event emitter that you can register to once. if you want multiple callbacks to be fired for the same event, you want to use an event emitter.

Event emitters are very important becausae they are at the core of Node. Mostly all other objects in node implement event emitters.

47. What’s an example of a built-in stream in Node that is both readable and writable?

Examples are transform streams: crypto.createCipher and zlib.createGzip. Streams are the next important thing in Node. If youre not using streams, you’re doing it wrong!

Sockets are duplex streams.

Allows you to not use memory when you don’t need to. Working with big data doesn’t require allocating a lot of memory in node, you just use stings

48. What are streams?

Streams are…

  • collections of data that might not be available all at once and don’t fit in memory
  • like arrays but special types of arrays (arrays that you don’t have but you only get once piece at a time)
  • don’t have to fit in memory because you might not want to handle all of the data at once

Gzip can compress a 10gb file to ~40mb.

Important: readable.pipe(writable).

a.pipe(b).pipe(c).pipe(d);

B and C have to be both readable and writable. A can just be readable and D can just be writable.