How does Node.js support multi-processor platforms, and does it fully utilize all processor resources?
Answer:
Since Node.js is by default a single thread application, it will run on a single processor core and will not take full advantage of multiple core resources. However, Node.js provides support for deployment on multiple-core systems, to take greater advantage of the hardware. The Cluster module is one of the core Node.js modules and it allows running multiple Node.js worker processes that will share the same port.
ViewWhat is the preferred method of resolving unhandled exceptions in Node.js?
Answer:
Unhandled exceptions in Node.js 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. An exception that has bubbled all the way up to the Process
level means that your application, and Node.js may be in an undefined state, and the only sensible approach would be to restart everything.
The preferred way is to add another layer between your application and the Node.js 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.
How does Node.js handle child threads?
Answer:
Node.js, in its essence, is a single thread process. It does not expose child threads and thread management methods to the developer. Technically, Node.js does spawn child threads for certain tasks such as asynchronous 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.js application, there are tools available to enable it, such as the ChildProcess module.
ViewWhat is “callback hell” and how can it be avoided?
Answer:
“Callback hell” refers to heavily nested callbacks that have become unweildy or unreadable.
An example of heavily nested code is below:
query("SELECT clientId FROM clients WHERE clientName='picanteverde';", function(id){
query("SELECT * FROM transactions WHERE clientId=" + id, function(transactions){
transactions.each(function(transac){
query("UPDATE transactions SET value = " + (transac.value*0.1) + " WHERE id=" + transac.id, function(error){
if(!error){
console.log("success!!");
}else{
console.log("error");
}
});
});
});
});
The primary method to fix callback hell is usually referred to as modularization. The callbacks are broken out into independent functions which can be called with some parameters. So the first level of improvement might be:
var logError = function(error){
if(!error){
console.log("success!!");
}else{
console.log("error");
}
},
updateTransaction = function(t){
query("UPDATE transactions SET value = " + (t.value*0.1) + " WHERE id=" + t.id, logError);
},
handleTransactions = function(transactions){
transactions.each(updateTransaction);
},
handleClient = function(id){
query("SELECT * FROM transactions WHERE clientId=" + id, handleTransactions);
};
query("SELECT clientId FROM clients WHERE clientName='picanteverde';",handleClient);
Even though this code is much easier to read, and we created some functions that we can even reuse later, in some cases it may be appropriate to use a more robust solution in the form of promises. Promises allow additional desirable behavior such as error propogation and chaining. Node.js doesn’t include much core support for promises, so one of the popular promise libraries should be used. One of the most popular is the Q promise library.
More information about promises and how they work can be found here.
Additionally, a more supercharged solution to callback hell is provided by generators, as these can resolve execution dependency between different callbacks. However, generators are much more advanced and it might be overkill to use them for this purpose. To read more about generators you can start with this post.
ViewConsider the following JavaScript code:
console.log("first");
setTimeout(function() {
console.log("second");
}, 0);
console.log("third");
The output will be:
first
third
second
Assuming that this is the desired behavior, and that we are using Node.js version 0.10 or higher, how else might we write this code?
Answer:
Node.js version 0.10 introduced setImmediate
, which is equivalent to setTimeout(fn, 0)
, but with some slight advantages.
setTimeout(fn, delay)
calls the given callback fn
after the given delay
has ellapsed (in milliseconds). However, the callback is not executed immediately at this time, but added to the function queue so that it is executed as soon as possible, after all the currently executing and currently queued event handlers have completed. Setting the delay to 0 adds the callback to the queue immediately so that it is executed as soon as all currently-queued functions are finished.
setImmediate(fn)
achieves the same effect, except that it doesn’t use the queue of functions. Instead, it checks the queue of I/O event handlers. If all I/O events in the current snapshot are processed, it executes the callback. It queues them immediately after the last I/O handler somewhat like process.nextTick
. This is faster than setTimeout(fn, 0)
.
So, the above code can be written in Node as:
console.log("first");
setImmediate(function(){
console.log("second");
});
console.log("third");
View
How do I find which version of V8 ships with a particular version of Node.js?
Answer:
Node.js provides a simple way to list all dependencies and respective versions that ship with a specific binary through the process
global object. In case of the V8 engine, type the following in your terminal to retrieve its version:
node -p process.versions.v8
View
Can we share sockets between processes to enable load balancing over server cores in NodeJS?
Answer:
Yes
Child processes can be spawned by using our child_process.fork()
API, and are designed to be easy to communicate with. Built upon that same interface is the cluster
module that helps us to share the sockets bettween processes to enable load balancing over server cores.
What's the output of following code snippet?
Promise.resolve(1)
.then((x) => x + 1)
.then((x) => { throw new Error('My Error') })
.catch(() => 1)
.then((x) => x + 1)
.then((x) => console.log(x))
.catch(console.error)
Answer
The short answer is 2
What's wrong with the following code snippet?
function checkApiKey (apiKeyFromDb, apiKeyReceived) {
if (apiKeyFromDb === apiKeyReceived) {
return true
}
return false
}
Answer:
When you compare security credentials it is crucial that you don't leak any information, so you have to make sure that you compare them in fixed time. If you fail to do so, your application will be vulnerable to timing attacks.
But why does it work like that?
V8, the JavaScript engine used by Node.js, tries to optimize the code you run from a performance point of view. It starts comparing the strings character by character, and once a mismatch is found, it stops the comparison operation. So the longer the attacker has right from the password, the more time it takes.
To solve this issue, you can use the npm module called cryptiles.
function checkApiKey (apiKeyFromDb, apiKeyReceived) {
return cryptiles.fixedTimeComparison(apiKeyFromDb, apiKeyReceived)
}
View
What's wrong with the code snippet?
new Promise((resolve, reject) => {
throw new Error('error')
}).then(console.log)
Answer:
As there is no catch
after the then
. This way the error will be a silent one, there will be no indication of an error thrown.
To fix it, you can do the following:
new Promise((resolve, reject) => {
throw new Error('error')
}).then(console.log).catch(console.error)
If you have to debug a huge codebase, and you don't know which Promise can potentially hide an issue, you can use the unhandledRejection
hook. It will print out all unhandled Promise rejections.
process.on('unhandledRejection', (err) => {
console.log(err)
})
View
When are background/worker processes useful? How can you handle worker tasks?
Answer:
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.
ViewWhat are Promises?
Answer:
Promises are a concurrency primitive, first described in the 80s. Now they are part of most modern programming languages to make your life easier. Promises can help you better handle async operations.
An example can be the following snippet, which after 100ms prints out the result
string to the standard output. Also, note the catch
, which can be used for error handling. Promises are chainable.
new Promise((resolve, reject) => {
setTimeout(() => {
resolve('result')
}, 100)
})
.then(console.log)
.catch(console.error)
View
What's your favourite HTTP framework and why?
Answer:
There is no right answer for this. The goal here is to understand how deeply one knows the framework she/he uses, if can reason about it, knows the pros, cons.
ViewWhat's a test pyramid? How can you implement it when talking about HTTP APIs?
Answer:
A test pyramid describes that when writings test cases there should be a lot more low-level unit tests than high level end-to-end tests.
When talking about HTTP APIs, it may come down to this:
What's a stub? Name a use case.
Answer:
Stubs are functions/programs that simulate the behaviours of components/modules. Stubs provide canned answers to function calls made during test cases. Also, you can assert on with what these stubs were called.
A use-case can be a file read, when you do not want to read an actual file:
var fs = require('fs');
var readFileStub = sinon.stub(fs, 'readFile', function (path, cb) {
return cb(null, 'filecontent');
});
expect(readFileStub).to.be.called;
readFileStub.restore();
View
Why npm shrinkwrap is useful?
Answer:
This command locks down the versions of a package's dependencies so that you can control exactly which versions of each dependency will be used when your package is installed. - npmjs.com
It is useful when you are deploying your Node.js applications - with it you can be sure which versions of your dependencies are going to be deployed.
ViewWhat's the difference between operational and programmer errors?
Answer:
Operation errors are not bugs, but problems with the system, like request timeout or hardware failure.
On the other hand programmer errors are actual bugs.
ViewWhat tools can be used to assure consistent style?
Answer:
You have plenty of options to do so:
These tools are really helpful when developing code in teams, to enforce a given style guide and to catch common errors using static analysis.
ViewWhat's the event loop?
Answer:
Node.js runs using a single thread, at least from a Node.js developer's point of view. Under the hood Node.js uses many threads through libuv.
Every I/O requires a callback - once they are done they are pushed onto the event loop for execution
ViewHow can you listen on port 80 with Node?
Answer:
You should not try to listen with Node on port 80 (in Unix-like systems) - to do so you would need superuser rights, but it is not a good idea to run your application with it.
Still, if you want to have your Node.js application listen on port 80, here is what you can do. Run the application on any port above 1024, then put a reverse proxy like nginx in front of it.
View© 2017 QuizBucket.org