Unexpected synchronous behaviour when using nodejs events module - javascript

I am using Node Events module for executing my function asynchronously.
var events = require('events');
var eventEmitter = new events.EventEmitter();
eventEmitter.on('myEvent', f2);
function f1(x, y) {
console.log('got', x, y)
eventEmitter.emit('myEvent', x, y);
eventEmitter.emit('myEvent', x, y);
eventEmitter.emit('myEvent', x, y);
console.log('done')
}
var count = 0
function f2(x, y) {
count++;
console.log('from f2', x, y, count)
}
f1(1, 2)
Its output is
alok#alok-HP-Laptop-14s-cf3xxx:~/tmp/test-node$ node alok.js
got 1 2
from f2 1 2 1
from f2 1 2 2
from f2 1 2 3
done
My expected output is
got 1 2
done
from f2 1 2 1
from f2 1 2 2
from f2 1 2 3
Why console.log('done') is running in last. or Why execution is synchronous?

Because that's how it works:
When the EventEmitter object emits an event, all of the functions attached to that specific event are called synchronously.
[..]
Asynchronous vs. synchronous
The EventEmitter calls all listeners synchronously in the order in which they were registered. This ensures the proper sequencing of events and helps avoid race conditions and logic errors. When appropriate, listener functions can switch to an asynchronous mode of operation using the setImmediate() or process.nextTick() methods:
const myEmitter = new MyEmitter();
myEmitter.on('event', (a, b) => {
setImmediate(() => {
console.log('this happens asynchronously');
});
});
myEmitter.emit('event', 'a', 'b');
https://nodejs.dev/en/api/v19/events

Related

How can I access array in function composition created by reduce? [duplicate]

I came across this pattern in redux compose function. I still don't understand how in the example below the functions are evaluated starting from the last and not from the first:
function f2(a) {
return a + a;
}
function f3(a) {
return a + a + a;
}
function f4(a) {
return a + a + a + a;
}
function f5(a) {
return a + a + a + a + a;
}
function compose(...funcs) {
return funcs.reduce(function x(a, b) {
return function y(...args) {
const temp = a(b(...args));
return temp;
};
});
}
const composedFunction = compose(f2, f3, f4, f5);
const result = composedFunction(2);
In the first reduce iteration the accumulator is f2 so we'll get f2(f3(2))=12. In the next iteration we'll call f4(12)=48. In the last iteration we'll call f5(48)=240. So the evaluation order is f5(f4(f2(f3(2)))). But using console.log I see that the evaluation order is f2(f3(f4(f5(2)))) which is also 240 by coincidence.
As far as I understand the function y is called for all array elements so why only the last function gets 2 as the parameter?
Let's step through the code with a very simple example:
compose(f2, f3, f4)
As no initial value was passed to reduce, it will start with the first (f2) and the second (f3) value of the array and call the callback with that, x gets called with a being f2 and b being f3. Now x does'nt do anything, it just returns function y that can access a and b through a closure.
Reduce will now continue to the third element, the first argument being the result of the previous callback (the closured y), and the second argument being f4. Now x gets called again, and another closure is created over y, y gets the finally returned from the whole function.
If we try to visualize thus closured function it'll be:
y { // closure of y
a -> y { // a references another closure of y
a -> f3,
b -> f2
},
b -> f4
}
Now you call that closured y and pass 2 into it, that will call b (f4) and pass the result to the call to a (closured y).
a ( b(...args))
y { ... } ( f4(2) )
Now that closured y will do the same:
a ( b ( ...args))
f2( f3( f4( 2 ) ) )
Hint: It is sometimes really difficult to keep track of closured values, therefore the console provides you with great utilities to keep track of them: Open your code in the consoles "debugger" tab, click on the line numbers where the function calls are to attach breakpoints, then run the code again, the execution will yield whenever a breakpoint is reached and you can see the values of all variables (including closured ones).
The reduce is not calling the functions f2, f3, f3, f5, but it is creating a function from those. This is the value of the accumulator in each iteration. Note that the value is a function and not a result from execution of the function.
1:a=f2;b=f3;return value(NOT TEMP but function y)=f2(f3(...args))
2:a(prev return value)=f2(f3(...args));b=f4;return value=f2(f3(f4(...args)))
and so on....
The compose function can be re-written as:
function compose(...funcs) {
return funcs.reduce(function (a, b) {
return function (arg) {
const temp = a(b(arg));
return temp;
};
});
}
After the first iteration, the returned function which is passed in as the next accumulator is:
function (arg) { // R1
return f2(f3(arg));
}
After the second iteration, the returned function which is passed in as the next accumulator is:
function (arg) { // R2
return R1(f4(arg));
}
And finally, the returned function assigned to composedFunction is:
function (arg) { // composedFunction
return R2(f5(arg));
}
So running composedFunction(2) and going back up the chain:
f5(2) returns 10
R2(10) returns R1(f4(10))
which is R1(40)
R1(40) returns f2(f3(40))
which is f2(120)
which is 240
Hopefully that's sufficient.
It can be written as a single call as:
function composedFunction(arg) {
return f2(f3(f4(f5(arg))));
}

Why does the first line in the reduce asynchronous function run multiple times before the remaining lines?

I have the below piece of code, I run it as it is, node filename.js, node version 14.16.0.
(async () => {
const add2 = a => a + 2;
const mult3 = a => a * 3;
const square = a => a * a;
const asyncAdd3 = a => new Promise(resolve => setTimeout(() => resolve(a), 100));
// composedFunc(2);
// Implement compose
const compose = (...args) => {
return (value) => {
return args.reduce(async (value, fn) => {
console.log(1);
var resolvedValue = await value;
console.log(2);
const returnVal = await fn(resolvedValue);
console.log(3);
return returnVal;
}, value)
}
}
const composedFunc = compose(add2, mult3, square, asyncAdd3);
console.log(await composedFunc(2));
})();
The output is as follows:
1
1
1
1
2
3
2
3
2
3
2
3
144
I don't understand why 1 gets printed four times before it goes to 2 and 3.. the below is what I was expecting to happen:
1
2
3
1
2
3
1
2
3
1
2
3
144
reduce takes the first value from the array and calls the callback with it (the current value) and the initial value (the accumulator).
The callback logs 1
The callback reaches an await statement next to a promise so it goes to sleep while it waits for the promise to resolve
A promise is returned to the calling function (the internals of reduce)
reduce takes the second value from the array and calls the callback with it (the current value) and the Promise that was returned by the previous step (the accumulator).
And so on.
When it gets to the end of the array, and everything else synchronous has finished, then the event loop checks to see if any Promises have resolved. At that point the first instance of the callback is woken up again.
You can't usefully use asynchronous functions as the callback for reduce.
Often you can use const resulting_array = await Promise.all( your_array.map( async_function ) ) to get a list of values and then use resulting_array.reduce().

How to run two setTimeout tasks in parallel?

I'm reading YDKJS and early on we are talking about the difference between Async, Parallel and Concurrent Code.
I have a simple Async example:
let output = 0;
const bar = (cb) => setTimeout(cb, Math.random() * 1000);
const foo = (cb) => setTimeout(cb, Math.random() * 1000);
bar( () => {
output = 1;
});
foo( () => {
output = 2
});
setTimeout(() => {
// This Async code should have 2 different outputs
output;
}, 2000);
The above code can have the 2 answers based on the Math.random timer and the mutable output:
However, I'd like to add a bit more complexity and convert foo and bar to run in parallel... I don't have much understanding on how I can achieve this:
Question: How can we update the code below, so that bar and foo are run in parallel and therefore, output has more than 2 possible outcomes?
Note: this is purely for learning purposes... I want to see the race conditions occure.
let inputA = 10;
let inputB = 11;
const bar = (cb) => setTimeout(cb, Math.random() * 1000);
const foo = (cb) => setTimeout(cb, Math.random() * 1000);
bar( () => {
inputA++;
inputB = inputB * inputA;
inputA = inputA + 3;
});
foo( () => {
inputB--;
inputA = 8 + inputB;
inputB = inputA * 2;
});
setTimeout(() => {
// This Parallel code should have more than 2 outputs;
console.log(inputA, inputB);
}, 2000);
The race condition you're looking to invoke isn't possible in ordinary Javascript, luckily. Any time you have a synchronous function, once control flow is passed to that function, that function is absolutely guaranteed to run to the end (or throw) before any other Javascript in the environment runs.
For example, given 1000 tasks which are scheduled by setTimeout to occur in the next 1-2 seconds (randomly), and you also invoke the following function after 1.5 seconds:
const fn = () => {
console.log('1');
for (let i = 0; i < 1e8; i++) {
}
console.log('2');
};
Once fn starts, it will run all of its code (synchronously) before the next random function runs. So even if the random functions call console.log, it is still guaranteed that, in the above situation, 2 will be logged right after 1.
So, in your original example, there are only 2 possibilities:
bar's callback runs first, and completely finishes, then foo's callback runs, and completely finishes. Or:
foo's callback runs first, and completely finishes, then bar's callback runs, and completely finishes.
Nothing else is possible, even if the random timeouts land on exactly the same number. Control flow can only be in exactly one place in the code at any given time.
For your original question, you want to see them run in parallel. You can use Promise.all to run multiple async tasks, it will waits for all async tasks resolved and return an output array.
Promise.all executes async tasks by iterating them(in series), not technically executes them in parallel, but they are running in parallel. It will give you a result when all async tasks resolved or rejected if any one of them failed.
Or you can just run them 1 by 1 without Promise.all. they won't block each other, so still in parallel, but you Promise.all just help you handle callback results in one place.
The output will be either 12 or 20, depends on random timeout you set for bar and foo functions.
For race condition, only the setTimeout functions are asynchronous, but all operations in callbacks are synchronous and non-blocking, so the thread won't jump from operations in one callback to another callback unless all operations in that callback are finished.
But in JS, you can still have data race when using SharedArrayBuffer which needs Atomics object to prevent data race.
let output = 0;
let inputA = 10;
let inputB = 11;
const bar = (cb) => setTimeout(cb, Math.random() * 1000);
const foo = (cb) => setTimeout(cb, Math.random() * 1000);
bar( () => {
inputA++;
inputB = inputA;
output = inputA + 1;
});
foo( () => {
inputB--;
inputA = inputB;
output = inputB * 2;
});
Promise.all([bar(),foo()])
.then(output => console.log('foo and bar tasks finished with output ',output));
setTimeout(() => {
console.log('output variable value: ', output)
}, 2000);

Are node.js event's handlers executed when the calling stack is empty?

I used to think that code related to node.js events are asynchronous. But the following example doesn't stick to that :
var EventEmitter = require('events').EventEmitter;
var emitter = new EventEmitter();
emitter.on('foo', function () {
console.log('Foo handler');
});
emitter.emit('foo');
console.log('Synchronous code!');
The 'foo' event should be added to the eventQueue and processed after the main function. But 'Synchronous Code' is displayed before 'Foo handler'. Why?
Do the events raised by emitter.emit() gets pushed to the eventsQueue in node ? If no, which ones do ?
Cause the Event Loop.
emitter.on and emitter.emit will be scheduled after this context execution.
like you're doing:
setImmediate(() => console.log('after Sync code in this context'))
console.log('Synchronous code!')
Another example
'use strict'
// handlers are executed in the order in which they are registered
console.log('Expected order: 1 2 a c b')
process.on('asd', () => console.log('a'))
function test () {
setTimeout(() => {
process.on('asd', () => console.log('b'))
}, 100)
process.on('asd', () => console.log('c'))
setTimeout(() => {
process.emit('asd')
}, 200)
console.log('2')
}
console.log('1')
test()
Not all Callbacks in JS or Node JS Are asynchronous.
Example array sort ,map ,reduce etc.It is
clearly mentioned in the docs that the
The EventEmitter calls all listeners synchronously in the order in
which they were registered.
So you get this behaviour.

JavaScript function composition by chaining

I have checked the possibility of duplicate question,
and cannot find the exact solution.
I wrote some function chain code in JavaScript as below, and works fine.
var log = function(args)
{
console.log(args)
return function(f)
{
return f;
};
};
(log('1'))(log('2'))(log('3'))(log('4'));
//1
//2
//3
//4
I want to make this lazy evaluation.
Or to compose function.
var log = function(args)
{
var f0 = function()
{
return console.log(args);
};
return function(f1)
{
return function()
{
f0();
return f1;
};
};
};
var world = (log('1'))(log('2'))(log('3'))(log('4'));
console.log(world);
//should be just a function,
// but in fact
//1
//[function]
world();
//should be
//1
//2
//3
//4
// but in fact
// 2
Something is very wrong.
Can you fix it?
Thanks.
This question is resolved, but there is further
async issue as shown in comment discussion
When we have
// unit :: a -> IO a
var unit = function(x)
{
return function()
{
return x;
};
};
// bind :: IO a -> (a -> IO b) -> IO b
var bind = function(x, y)
{
return function()
{
return y(x())();
};
};
// seq :: IO a -> IO b -> IO b
var seq = function(x, y)
{
return function()
{
return x(), y();
};
};
var action = function(x)
{
return function(y)
{
return y ? action(seq(x, y)) : x();
};
};
var wrap = function(f)
{
return function(x)
{
return action(function()
{
return f(x);
});
};
};
var log = wrap(console.log);
// -- runtime --
// HACK: when `world` is modified by passing a function,
// the function will be executed.
Object.defineProperties(window,
{
world:
{
set: function(w)
{
return w();
}
}
});
We also often want async chain reactions badly.
var asyncF = function(callback)
{
setTimeout(function()
{
for (var i = 0; i < 1000000000; i++)
{
};
callback("async process Done!");
}, 0);
};
var async = wrap(asyncF(function(msg)
{
world = log(msg);
return msg;
}));
Now,
world = (log(1))(async)(log(3));
//1
//3
//async process Done!
So far nice and smooth, now we try to use bind
world = (log(1))
(bind((async), (log(x))));
//should be
//1
//async process Done!
//3
//in fact
//ReferenceError: x is not defined
Could you modify to make this work, please?
one more about retrun x, y; multiple value
I don't understand
// seq :: IO a -> IO b -> IO b
var seq = function(x, y)
{
return function()
{
return x(), y();
};
};
as the library author mentions
Note that this is not possible in Haskell because one function can't return two results. Also, in my humble opinion, it looks ugly.
I agree, and don't know what this
return x(), y();
multiple return value.
I googled and searched here, but could not find an answer.
What is this??
(just in case, I will chose this hack for the syntax)
Thanks!
So if I understand the question correctly, you want to chain IO actions in JavaScript. To do so, you first need to define what an IO action is. One way to think of an IO action is that it is simply a function which takes no arguments. For example:
// log :: a -> IO b
function log(x) {
return function () { // IO action
return console.log(x);
};
}
One advantage of representing an IO action as a function with no arguments is that it is the same representation for thunks (unevaluated expressions). Thunks are the things that enable lazy evaluation in languages like Haskell. Hence you get laziness for free.
Now composition. How do you compose two IO actions in JavaScript? In Haskell, you use the >> operator to sequence IO actions, which is usually defined in terms of >>= (a.k.a. bind) as follows:
(>>=) :: Monad m => m a -> (a -> m b) -> m b
(>>) :: Monad m => m a -> m b -> m b
x >> y = x >>= \_ -> y
It is easy to write an equivalent bind function for our IO actions in JavaScript:
// bind :: IO a -> (a -> IO b) -> IO b
function bind(x, y) {
return function () {
return y(x())();
};
}
Suppose you have an IO action x :: IO a. Since it's just a function with no arguments, when you call it it's equivalent to evaluating the IO action. Hence x() :: a. Feeding this result to the function y :: a -> IO b results in the IO action y(x()) :: IO b. Note that the entire operation is wrapped in a superfluous function for laziness.
Similarly, it is just as straightforward to implement the >> operator. Let's call it seq as in “sequence”.
// seq :: IO a -> IO b -> IO b
function seq(x, y) {
return function () {
return x(), y();
};
}
Here we evaluate the IO expression x, don't care about its result and then return the IO expression y. This is exactly what the >> operator does in Haskell. Note that the entire operation is wrapped in a superfluous function for laziness.
Haskell also has a return function which lifts a value into a monadic context. Since return is a keyword in JavaScript, we'll call it unit instead:
// unit :: a -> IO a
function unit(x) {
return function () {
return x;
};
}
As it turns out there's also a sequence operator in Haskell which sequences monadic values in a list. It can be implemented in JavaScript for IO actions as follows:
// sequence :: [IO a] -> IO [a]
function sequence(array) {
return function () {
var list = array;
var length = list.length;
var result = new Array(length);
var index = 0;
while (index < length)
result[index] = list[index++]();
return result;
};
}
That's all we need. Now we can write:
var world = sequence([log("1"), log("2"), log("3"), log("4")]);
world();
// 1
// 2
// 3
// 4
Hope that helps.
Yes, it is indeed possible to chain IO actions using your syntax. However, we'll need to redefine what an IO action is:
function action(x) {
return function (y) {
return y ? action(seq(x, y)) : x();
};
}
Let's understand what the action function does using an example:
// log :: a -> IO b
// log :: a -> IO r -> IO r
function log(x) {
return action(function () {
return console.log(x);
});
}
Now you can do:
log("1")(); // :: b
log("1")(log("2")); // :: IO r
In the first case we evaluated the IO action log("1"). In the second case we sequenced the IO actions log("1") and log("2").
This allows you to do:
var world = (log("1"))(log("2"))(log("3"))(log("4"));
world();
// 1
// 2
// 3
// 4
In addition you can also do:
var newWorld = (world)(log("5"));
newWorld();
// 1
// 2
// 3
// 4
// 5
And so on....
Everything else remains the same. Note that this is not possible in Haskell because one function can't return two results. Also, in my humble opinion, it looks ugly. I prefer using sequence instead. However, this is what you wanted.
Let's look at what happens here:
var log = function(args)
{
var f0 = function()
{
return console.log(args);
};
return function(f1)
{
return function()
{
f0();
return f1;
};
};
};
And inline just a bit:
var log = function(args) {
return function(f1) {
return function() {
console.log(args);
return f1;
};
};
};
So we're returning a function f which accepts a function f1, and returns a function g which does logic and returns f1. Quite a mouthful! Your question is why does
(log('1'))(log('2'))(log('3'));
Log 1. I did away with the log('4') since going to 3 is enough to show your described case. To answer that let's play compiler and do the inlining game!
(log('1'))(log('2'))(log('3'))
// =>
(
function (f1) {
return function () {
console.log('1');
return f1;
}
}
)(
function (f1) {
return function () {
console.log('2');
return f1;
}
}
)(
function (f1) {
return function () {
console.log('3');
return f1;
}
}
)
Simple substitution. I took each instance of log(something), replaced it with the contents of the function, replaced the argument with the value passed. Let's do it again!
(
function () {
console.log('1');
return function (f1) {
return function () {
console.log('2');
return f1;
}
};
}
)(
function (f1) {
return function () {
console.log('3');
return f1;
}
}
)
This one is a bit trickier to follow: I expanded the first function call. The topmost function received an argument f1 to which we just supplied a value, so I went into the function and replaced every occurrence of f1 with the given value (the result of log('2')), just like with the log argument.
Look over what happened here again if you still don't follow, but my suggestion is doing it yourself: Copy the snippet into your favourite code editor and do the expansion yourself.
Now you may see why the log('1') was called. The next thing we, the compiler, need to do is take care of the next function call. And whadya know, the first line in that function is a console.log! Better do it!
What can we do!?
I don't know Haskell or the IO Monad, but as you currently planned, I do not think you can do what you want with basic functions, not like that. If you can say what problem you want to solve using this...erm...pattern, maybe we can help!
This is because you are just returning and returning everything...
There are three thing printed in the output:
1
function ()
{
f0();
return f1;
}
2
1) first output: 1
this is because:console.log(args) is only executed once in your chaining, because f0 is executed only once at the last where it finds args to be 1(because of returning each nested function, what value you return at the last is a function f1 which executes f0() when the value of args is 1.
then it prints 1 to the console.
2) second output the function f1
the return f1;(which is returned to the function when you passed args as 1) executed at the last returns
function ()
{
f0();
return f1;
}
back to the variable world, hence only the inner nested function is printed to the console.
3) Third output: 2
then when you execute the functionworld(),
Again the function f1 is executed directly(see there is just a little difference between world and world()) but this time the returned function for when you passed args as 2.
Reason: world will output only the function, world() will execute the function.
When you write world(), at the last time where the function f1 is returned the value for args was 2 is directly executed.
I know I have terribly worded the answer.. but hope this helps (hope you understand)
While executing
var world = (log('1'))(log('2'))(log('3'))(log('4'));
(log('1')) is executed first which returns a function which takes in (log('2')).
This anonymous function starts executing but doesn't accept any argument.
log('3') is neglected. This can verified by
if(typeof(arguments[0]) == 'function'){
console.log("Got a neglected argument");
console.log(arguments[0]());
}
After executing f0(); (which prints 1 to screen), we return f1 which points to function returned by log('2'), this takes in log('4');
This can be verified by doing:
world()()()
this outputs:
2
4
undefined

Categories