Convert asynchronous/callback method to blocking/synchronous method - node.js

Is is possible to convert an asynchronous/callback based method in node to blocking/synchronous method?
I'm curious, more from a theoretical POV, than a "I have a problem to solve" POV.
I see how callback methods can be converted to values, via Q and the like, but calling Q.done() doesn't block execution.

The node-sync module can help you do that. But please be careful, this is not node.js way.

To turn asynchronous functions to synchronous in 'multi-threaded environment', we need to set up a loop checking the result, therefore cause blocking.
Here’s the example code in JS:
function somethingSync(args){
var ret; //the result-holding variable
//doing something async here...
somethingAsync(args,function(result){
ret = result;
});
while(ret === undefined){} //wait for the result until it's available,cause the blocking
return ret;
}
OR
synchronize.js also helps.

While I would not recommend it, this can easy be done using some sort of busy wait. For instance:
var flag = false;
asyncFunction( function () { //This is a callback
flag = true;
})
while (!flag) {}
The while loop will continuously loop until the callback has executed, thus blocking execution.
As you can imagine this would make your code very messy, so if you are going to do this (which I wouldn't recommend) you should make some sort of helper function to wrap your async function; similar to Underscore.js's Function functions, such as throttle. You can see exactly how these work by looking at the annotated source.

Related

Node - Run code after return statement

Is there any way to run a block of code after the return of a function in node js?
Something like this:
function f() {
#do stuff
#return result
#do more stuff
}
No, there is no way to do that in the way that you show. return exits from the containing function and statements immediately after the return statement do not execute (in fact they are dead code).
(Per your comments) If what you're really trying to do is to execute something "out of band" that the rest of the function (including the return value) does not depend upon, you could schedule that code to run later. For example, you could use setTimeout(), process.nextTick() or setImmediate().
function f() {
// do stuff
setTimeout(function() {
// do some stuff here that will execute out of band
// after this function returns
}, 0);
return someVal;
}
There are legit uses for things like this where you want to execute something soon, but you don't want it to get in the way of the current operation. So, you'd essentially like to queue it to execute when the current activity is done.
The answer is No. After you return the function will stop execution. You can consider using a better flow control to run the code like Async/Await or Promise
You use the return statement to stop execution of a function and return the value of expression. according to the following doc
https://learn.microsoft.com/en-us/scripting/javascript/reference/return-statement-javascript

What do fibers/future actually do?

What does the line of code below do?
Npm.require('fibers/future');
I looked online for examples and I came across a few like this:
Future = Npm.require('fibers/future');
var accessToken = new Future();
What will accessToken variable be in this case?
Question is a bit old but my 2 cents:
As Molda said in the comment, Future's main purpose is to make async things work synchronously.
future instance comes with 3 methods:
future.wait() basically tells your thread to basically pause until told to resume.
future.return(value), first way to tell waiting future he can resume, it's also very useful since it returns a value wait can then be assigned with, hence lines like const ret = future.wait() where ret becomes your returned value once resumed.
future.throw(error), quite explicit too, makes your blocking line throw with given error.
Making things synchronous in javascript might sound a bit disturbing but it is sometimes useful. In Meteor, it's quite useful when you are chaining async calls in a Meteor.method and you want its result to be returned to the client. You could also use Promises which are now fully supported by Meteor too, I've used both and it works, it's up to your liking.
A quick example:
Meteor.methods({
foo: function() {
const future = new Future();
someAsyncCall(foo, function bar(error, result) {
if (error) future.throw(error);
future.return(result);
});
// Execution is paused until callback arrives
const ret = future.wait(); // Wait on future not Future
return ret;
}
});

Understanding try and catch in node.js

I'm new to coding. Trying to understand why try...catch isn't supposed to work in node.js. I've created an example, but contrary to expectations, try...catch seems to be working. Where am I going wrong in my understanding ? Please help.
function callback(error) { console.log(error); }
function A() {
var errorForCallback;
var y = parseInt("hardnut");
if (!y) {
throw new Error("boycott parsley");
errorForCallback = "boycott parsley for callback";
}
setTimeout(callback(errorForCallback),1000);
}
try {
A();
}
catch (e) {
console.log(e.message);
}
// Output: boycott parsley
// Synchronous behaviour, try...catch works
-----------Example re-framed to reflect my understanding after reading answer below----------
function callback(error) { console.log(error); }
function A() {
var errorForCallback;
setTimeout(function(){
var y = parseInt("hardnut");
if (!y) {
// throw new Error("boycott parsley");
errorForCallback = "boycott parsley for callback";
}
callback(errorForCallback);
}, 1000);
}
try {
A();
}
catch (e) {
console.log(e.message);
}
// Output: boycott parsley for callback
// Asynchronous behaviour
// And if "throw new Error" is uncommented,
// then node.js stops
The try-catch approach is something that works perfectly with synchronous code. Not all the programming that you do in Node.js is asynchronous and so in those pieces of synchronous code that you write you can perfectly use a try-catch approach. Asynchronous code, on the other hand, does not work that way.
For instance, if you had two function executions like this
var x = fooSync();
var y = barSync();
You would expect three things, first that barSync() would be executed only after fooSync() has finished, and you would expect that x would contain whatever value is returned by the execution of fooSync before barSync() is executed. Also you would expect that if fooSync throws an exception, barSync is never executed.
If you would use a try-catch around fooSync() you could guarantee that if fooSync() fails you can catch that exception.
Now, the conditions completely change if you would have a code like this:
var x = fooAsync();
var y = barSync();
Now imagine that when fooAsync() is invoked in this scenario, it is not actually executed. It's just scheduled for execution later on. It is as if node would have a todo list, and at this moment it is too busy running your current module, and when it finds this function invocation, instead of running it, it simply adds it to the end of its todo list.
So, now you cannot guarantee that barSync() will run before fooAsync(), as a matter of fact, it probably won't. Now you don't control the context in which fooAsync() is executed.
So, after scheduling the fooAsync() function, it immediately moves to execution of barSync(). So, what can fooAsync() return? At this point nothing, because it has not run yet. So x above is probably undefined. If you would put try-catch around this piece of code it would be pointless, because the function will not be executed in the context of this code. It will be executed later on, when Node.js checks if there are any pending tasks in its todo list. It will be executed in the context of another routine that is constantly checking this todo list, and this only thread of execution is called an event loop.
If your function fooAsync() gets to fail, it will fail in the context of execution of this thread running the event loop and therefore it would not be caught by your try-catch statement, at that point, that module above may have probably finished execution.
So, that is why in asynchronous programing you cannot either get a return value, neither can you expect to do a try-catch, because you code is evaluated somewhere else, in another context different from the one where you think you invoked it. It is as if you could would have done something like this instead:
scheduleForExecutionLaterWhenYouHaveTime(foo);
var y = barSync();
And that's the reason why asynchronous programming requires other techniques to determine what happened to your code when it finally runs. Typically this is notified through a callback. You define a callback function which is called back with the details of what failed (if anything) or what your function produced and then you can react to that.

Sequence of code execution in Node.js app

I have always wondered about this and have never found a convincing answer.
Please consider the following case:
var toAddress = '';
if(j==1)
{
toAddress="abc#mydomain.com";
}
else
{
toAddress="xyz#mydomain.com";
}
sendAlertEmail(toAddress);
Can I be certain that by the time my sendAlertEmail() function is called, I will have 'toAddress' populated?
For code like the sample you provided:
var toAddress = '';
if(j==1)
{
toAddress="abc#mydomain.com";
}
else
{
toAddress="xyz#mydomain.com";
}
sendAlertEmail(toAddress);
You can definitely be certain that it is strictly sequential. That is to say that the value of toAddress is either "abc#mydomain.com" or "xyz#mydomain.com".
But, for code like the following:
var toAddress = '';
doSomething(function(){
if(j==1)
{
toAddress="abc#mydomain.com";
}
else
{
toAddress="xyz#mydomain.com";
}
});
sendAlertEmail(toAddress);
Then it depends on whether the function doSomething is asynchronous or not. The best place to find out is the documentation. The second best is looking at the implementation.
If doSomething is not asynchronous then the code execution is basically sequential and you can definitely be certain that toAddress is properly populated.
However, if doSomething is asynchronous then you can generally be certain that the code execution is NOT sequential. Since that is one of the basic behavior of asynchronous functions - that they return immediately and execute the functions passed to them at a later time.
Not all functions that operate on functions are asynchronous. An example of synchronous function is the forEach method of arrays. But all asynchronous functions accept functions as arguments. That's because it's the only way to have some piece of code executed at the end of the asynchronous operation. So whenever you see functions taking functions as arguments you should check if it's asynchronous or not.
Node.js is single threaded (or at least the JS execution is) so since all the above code is synchronous and lined up to all occur during the same tick it will run in order and thus toAddress must be populated.
Things get complicated once you introduce an asynchronous function. In the asynchronous case it it possible for variable to shift between lines, since ticks occur between them.
To clarify during each tick the code is simply evaluated from the top of the execution to the bottom. During the first tick the scope of execution is the whole file, but after that it's callbacks and handlers.
The code that you wrote was pretty simple to point out the asynchronous behavior. Take a look at this code :
var toAddress = 'abc#mydomain.com';
if(j==1)
{ func1(toAddress); }
else
{ func2(toAddress); }
sendAlertEmail(toAddress);
There is no guarantee that sendAlertEmail will execute only after func1 or func2 (the if else conditional) has been executed. In node functions return immediately when they are called and execute the next function called. If you want to make sure they execute sequentially use callbacks or use a library like async.

NodeJS - Can't implement asynchronous function

I'm newbie in NodeJs. This is my code for learning asynchronous function.
//--------------------- MAIN ---------------
console.log("Endpoint 1\r\n");
testThread(1000000000,function (result){
console.log(">>>>"+result+"\r\n");
});
console.log("Endpoint 2\r\n");
//------------------------------------------
function testThread(data,callback) {
//take a long time
for(j=0;j<data;j++) {
a = 122342342342424242431*3543652636364;
}
//
callback(a);
}
Run it:
node testthread.js
Always the result is:
Endpoint 1
>>>>4.335387639806787e+32
Endpoint 2
System prints "Endpoint 1", take 2 seconds, it prints ">>>>4.335387639806787e+32" after then it prints "Endpoint 2"
I'm not found the asynchronous here.
It should be:
Endpoint 1
Endpoint 2
>>>>4.335387639806787e+32
Please explain me.
Asynchronous functions are functions that call other functions that are asynchronous. There is not other way to implement asynchronous functions in javascript/node.js. Which at first looks like a chicken and egg problem doesn't it? How can one write an asynchronous function if the requirement is that it must call another asynchronous function in order to be asynchronous?
The answer is that the lowest level asynchronous function must be implemented in C.
Fortunately, javascript/node.js has several built-in asynchronous functions implemented in C that we can use as building blocks in javascript to build our own asynchronous functions. Examples of such functions include the http.request() method, the socket.listen() method and probably the simplest setTimeout() and setInterval().
Here's an example of how one could rewrite your code to achieve asynchronous processing;
function long_task (repeat_number, callback) {
// setTimeout is asynchronous, so keep calling it until we're done
function loop () {
if (repeat_number > 0) {
repeat_number --;
setTimeout(loop,1);
}
else {
callback("I'm done!");
}
}
loop();
}
console.log("calling long task");
long_task(10000,function(x){console.log(x)});
console.log("long task started");
This is a total synchronous code and as node.js is single threaded it wont start a second thread this way.
There are several asynchronous tasks like network requests or database calls, but this one is not.
You would have to spawn a child process to have this asynchronous.
See http://nodejs.org/api/child_process.html for more information

Resources