1

I am trying to work with node.js and node-java and trying to get my head wrapped around some concepts, and in particular how to write async method calls.

I think that, for a function in Java, myclass.x():

[In Java]:

Z = myclass.x(abc);

And:

[In node.js/node-java]:

myclass.x(abc, function(err,data) {
//TODO
Z = data;});

In other words, the myclass.x function gets evaluated using the parameter abc, and if no error, then the result goes into "data" which is then assigned to Z.

Is that correct?

Here's the thing (or one of the things) that I am confused about.

What happens if the function myclass.x() doesn't take any parameters?

In other words, it is normally (in Java) just called like:

Z = myclass.x();

If that is the case, how should the node.js code look?

myclass.x(, function(err,data) {
//TODO
Z = data;});

doesn't seem right, but:

myclass.x( function(err,data) {
//TODO
Z = data;});

also doesn't seem correct.

So what is the correct way to code the node.js code in this case?

Thanks in advance!!

Jim

EDIT 1: Per comments, I'm adding the specific code I'm working with is the last couple of commented out lines from this other question at:

node.js and node-java: What is equivalent node.js code for this java code?

These are the lines (commented out in that other question):

var MyFactoryImplClass = java.import("oracle.security.jps.openaz.pep.PepRequestFactoryImpl.PepRequestFactoryImpl");

var result = myFactoryImplClass.newPepRequest(newSubject, requestACTIONString ,requestRESOURCEString , envBuilt)

I tried to make the last line use an async call:

MyFactoryImplClass.getPepRequestFactory( function(err,data) {
    //TODO
    pepReqF1=data;})
javaLangSystem.out.printlnSync("Finished doing MyFactoryImplClass.getPepRequestFactory() and stored it in pepReqF1 =[" + pepReqF1 + "]");

But the output was showing the value of that pepReqF1 as "undefined".

Community
  • 1
  • 1
user555303
  • 1,146
  • 3
  • 20
  • 44
  • 2
    Your last code block is correct in Javascript. – jfriend00 Sep 23 '16 at 06:13
  • 3
    A callback function is just a normal parameter passed to a function call. In Javascript, a function is a first class object that can be passed just like any other objects. You can pass it in any position you want, first, second, last, etc... though the node.js async calling convention is to pass it last. – jfriend00 Sep 23 '16 at 06:25
  • @jfriend00, thanks. This question arose (in my mind) because I'm trying to port some Java code to a node.js app, and I'm running into problems with that process, and maybe those problems. The thing is that I have to call out to some Java classes/methods that are part of a commercial product, so I don't get to change the methods to be sync-friendly, i.e., I cannot change the methods in that commercial product. Anyway, so I am following what you said and changed a call that I thought was problematic, but when I do a println of the "Z" var, I am getting "undefined". – user555303 Sep 23 '16 at 06:45
  • You'd have to show the actual sequence of code for me to know what's going wrong. But, a common issue is that async callbacks are called sometime in the future (and you don't know when), so the only place you can use the value of `Z` reliably is INSIDE the callback function, not outside it. Async code cannot be made synchronous. You have to change the way you program to an async model using callbacks or promises. – jfriend00 Sep 23 '16 at 06:59
  • I've edited the original message to show the specific code. In what I tried, I was outputting the "Z" value in a println that was outside the callback function, so I guess that was why it was "undefined". When you say the value is only reliable inside the callback function that seem awfully restrictive? In my case, I can't change the Java class I am calling, so can I even invoke that class and its methods from node.js non-async? – user555303 Sep 23 '16 at 09:11
  • The difference is that Java (by default) does IO in a blocking way, meaning if you access the database or the filesystem, the thread is blocked until the access is complete and data is available. Node does this in *non-blocking* by default, and it provides you with a callback to pass to express what you want to happen when the data returns. While the data is being accessed (or written), the rest of the program can still execute. – Madara's Ghost Sep 23 '16 at 09:24
  • Ah. I guess that we (or I) all tend to learn in different ways and sometimes it just takes the right words. I just found this page (https://www.toptal.com/nodejs/top-10-common-nodejs-developer-mistakes) and the sentence at the end of #4 explained a lot to me ("Anything that needs to happen after a callback has fired needs to be invoked from within it.")! – user555303 Sep 23 '16 at 09:29
  • @jfriend00 and madara - I'd like to mark what you said as answers but it looks like they are comments and can't be changed to answers? – user555303 Sep 23 '16 at 18:17

2 Answers2

1

If calling the method with one parameter and a callback is:

myclass.x(abc, function(err, data) {
  // ...
});

Then calling a method with only a callback would be:

myclass.x(function(err, data) {
  // ...
});

The function(err, data) { } part is just a normal parameter just like abc. In fact, you can pass a named function with:

function namedFun(err, data) {
  // ...
}
myclass.x(abc, namedFun);

Or even:

var namedFun = function (err, data) {
  // ...
}
myclass.x(abc, namedFun);

Functions in JavaScript are first-class objects like strings or arrays. You can pass a named function as a parameter to some other function:

function fun1(f) {
  return f(10);
}
function fun2(x) {
  return x*x;
}
fun1(fun2);

just like you can pass a named array:

function fun3(a) {
  return a[0]
}
var array = [1, 2, 3];
fun3(array);

And you can pass an anonymous function as a parameter:

function fun1(f) {
  return f(10);
}
fun1(function (x) {
  return x*x;
});

just like you can pass an anonymous array:

function fun3(a) {
  return a[0]
}
fun3([1, 2, 3]);

There is also a nice shortcut so that instead of:

fun1(function (x) {
  return x*x;
});

You can write:

fun1(x => x*x);
rsp
  • 107,747
  • 29
  • 201
  • 177
0

Making my comment into an answer...

If the issue you're experiencing is that Z does not have the value you want when you are examining it, then that is probably because of a timing issue. Asynchronous callbacks happen at some unknown time in the future while the rest of your code continues to run. Because of that, the only place you can reliably use the result passed to the asynchronous callback is inside the callback itself or in some function you would call from that function and pass it the value.

So, if your .x() method calls it's callback asynchronously, then:

var Z;
myclass.x( function(err,data) {
    // use the err and data arguments here inside the callback
    Z = data;
});

console.log(Z);    // outputs undefined

// you can't access Z here.  Even when assigned 
// to higher scoped variables because the callback has not yet
// been called when this code executes

You can see this is a little more clearly by understanding the sequencing

console.log('A');
someAsyncFucntion(function() {
    console.log('B');
})
console.log('C');

This will produce a log of:

A
C
B

Showing you that the async callback happens some time in the future, after the rest of your sequential code has executed.


Java, on the other hand, primarily uses blocking I/O (the function doesn't return until the I/O operation is copmlete) so you don't usually have this asynchronous behavior that is standard practice in node.js. Note: I believe there are some asynchronous capabilities in Java, but that isn't the typical way things are done and in node.js, it is the typical ways things are done.

This creates a bit of an architectural mismatch if you're trying to port code that uses I/O from environment from another because the structure has to be redone in order to work properly in a node.js environment.

jfriend00
  • 683,504
  • 96
  • 985
  • 979