Javascript Wrapping Callback as Promise Equivalent in Java 8 using CompletableFuture - javascript

In Javascript, I can wrap a callback as a promise as folllows:
function subscribeAsCallback(request, callback) {
// ... async operation
const response = ...;
callback(response);
}
function subscribeAsPromise(request) {
return new Promise((resolve, reject) => {
subscribeAsCallback(request, (response) => {
resolve(response);
});
});
}
So that I can call it with
subscribeAsPromise(request).then(response => {
// handling response logic
});
And I would like to ask what is the equivalent of it in Java? Here is my code in Java, where I have no idea how to wrap the callback up.
public class DataSubscriber {
public void subscribeAsCallback(Request request, Consumer<Response> consumer) {
// ... async operation
Response response = ...;
consumer.accept(response);
}
public CompletableFuture<Response> subscribeAsPromise(Request request) {
// ... ?
// what is the equivalent of its Java version?
}
}
So that I can call the code as follows:
dataSubscriber.subscribeAsPromise(request).thenApply(response -> {
// handling response logic
});

I just think of a solution using CountDownLatch, though I don't think using CountDownLatch is a good idea, as it just block the thread from execution which wastes some resources. But it will be one possible solution for that.
public class DataSubscriber {
public void subscribeAsCallback(Request request, Consumer<Response> consumer) {
// ... async operation
Response response = ...;
consumer.accept(response);
}
public CompletableFuture<Response> subscribeAsPromise(Request request) {
return CompletableFuture.supplyAsync(() -> {
try {
final Response[] responeResult = { null };
CountDownLatch latch = new CountDownLatch(1);
subscribeAsCallback(request, new Consumer<Response>() {
public void accept(Response response) {
responeResult[0] = response;
latch.countDown();
}
});
latch.await();
return responseResult[0];
} catch (Exception ex) {
throw new RuntimeException(ex);
}
});
}
}
Though the code does not look very nice, it is the first solution I can think of. Hope there are other better answers so that I can learn upon.

You won't be able to pass callback into CompletableFuture. I personally find it easier to handle promises in JavaScript and definitely more verbose in java.
In your example, I don't see the point of passing in the anonymous function (response) => { resolve(response); } to resolve the promise or future since CompletableFuture provides a get() method to resolve the CompletableFuture, which is called after your line of code
CompletableFuture future = dataSubscriber.subscribeAsPromise(request).thenApply(response -> {
// handling response logic
});
// do this to "resolve" the future
future.get();
public class DataSubscriber {
// Please update the name to reflect the correct semantic meaning
public Response subscribeAsCallback(Request request) {
// ... async operation
Response response = ...;
return response;
}
public CompletableFuture<Response> subscribeAsPromise(Request request) {
return CompletableFuture.supplyAsync(this::subscribeAsCallback);
}
}

Related

Method does not wait for Promise to be resolved

I have a function that I'm trying to call and basically force it to wait for a response before continuing onto the next thing.
I have two functions, both are asynchronous.
The first one looks something like this, with all parameters that begin with an '_' to be used as callbacks:
async function formatJson(input, _sendToThirdParty, _handleLogs, _setDimensions)
{
...do some work here to format the payload
if(onlineConnectionRequired)
{
_setDimensions(itemToUpdate, object);
}
else {
// Do non-online based transformations here
}
...do more work after the above
}
Basically from that, I'm trying to call this method setDimensions which looks like this:
async function setDimensions(itemToUpdate, object) {
try
{
if(itemToUpdate != null)
{
console.log("Loading dimensions");
await Promise.resolve(function() {
ns.get(`inventoryItem/${object['Item ID']}?expandSubResources=true`)
.then((res) => {
console.log("Inventory Item Loaded. Updating dimensions...");
itemToUpdate.consignments.push(
{
consignmentID: object.conID,
barcode: object.barcode,
itemID: '', // leaving as empty for now
width : res.data.custitem_width,
length : res.data.custitem_length,
height : res.data.custitem_height,
weight : res.data.custitem_weight,
fragile: object.fragile === 'T' ? 1 : 0,
description: object.description
}
);
console.log("Dimensions Finalised");
})
});
}
}
catch(err)
{
console.log(err);
const message = `Error attempting to set the dimensions for ${object['Item ID']}`;
console.log(message);
throw new Error(message);
}
}
The problems I'm coming across are:
The code from the first method continues on before waiting for the promise to resolve, but I need it to wait so I can fully finish building up the payload before it continues on doing the next bits
If I try and include the await keyword before my call to _setDimensions(...) in the first method, I get an error "SyntaxError: await is only valid in async function", but I would've thought that it was an async function?
If anyone could help, that would be incredibly appreciated! Thank you!!
The correct design of your functions are below:
formatJson(input, (err, value) => {
if(err) {
// Error handler goes here
//console.log(err);
throw err;
} else {
// Implementation for working with returned value
console.log(value);
}
});
function formatJson(input, callback)
{
//...do some work here to format the payload
if(onlineConnectionRequired)
{
setDimensions(itemToUpdate, object)
.then((updatedItem) => {
// Implement anything here to work with your
// result coming from setDimensions() function
//console.log(updatedItem);
// Callback with null error and updatedItem as value
callback(null, updatedItem);
})
.catch((err) => {
// Callback with err object and null value
callback(err, null);
});
}
else {
// Do non-online based transformations here
}
//...do more work after the above
}
function setDimensions(itemToUpdate, object) {
try
{
if(inventoryItemID != null)
{
console.log("Loading dimensions");
return new Promise(function(resolve, reject) {
ns.get(`inventoryItem/${object['Item ID']}?expandSubResources=true`)
.then((res) => {
console.log("Inventory Item Loaded. Updating dimensions...");
itemToUpdate.consignments.push(
{
consignmentID: object.conID,
barcode: object.barcode,
itemID: '', // leaving as empty for now
width : res.data.custitem_width,
length : res.data.custitem_length,
height : res.data.custitem_height,
weight : res.data.custitem_weight,
fragile: object.fragile === 'T' ? 1 : 0,
description: object.description
}
);
console.log("Dimensions Finalised");
resolve(itemToUpdate);
})
.catch((err) => reject(err));
});
}
}
catch(err)
{
console.log(err);
const message = `Error attempting to set the dimensions for ${object['Item ID']}`;
console.log(message);
throw new Error(message);
}
}
Mistakes in your code:
Your formatJson function had async keyword but your formatJson function had callback functions named _sendToThirdParty, _handleLogs, _setDimensions. There are 3 types of implementation to create asynchronous codes. You can use callbacks, Promises or async/await. But Promises and async/await are the same except their uses cases and syntaxses. When you define a function as async fn() {...} it basically return a new Promise, so it is equal saying fn() { return new Promise(); }. Functions with callbacks have a shape like function(params, callback) { callback(cbParams); } you can use call callback function in a several branches in your function. But you only have single callback function, your code had 3 callback functions. Also note that functions with callback don't have async keyword. This is not valid because as I mentioned earlier, an async function will return a Promise. So you should not (but you can) define a function as async function(params, callback) like you did in your first method. This is definition is not wrong and it can work but it's not valid.
Your second method was an async function which was returning nothing. So I have changed it to normal function with returning a Promise.
Is the formatJson method beeing called inside an async method? It need to be, and before _setDimensions you need to add a await keyword.
And, as Daniel said, use the promise constructor.

Calling a Promise function inside Google Cloud Function

I am trying to issue an HTTP request to another web service, from a Google Cloud Function (GCF) that I have created. I need the HTTP request to complete and return that result inside of my GCF so that I can do something else with it.
My question is; What is the best way to use Promise inside a Google Cloud Function? Is what I am trying to do possible?
My code currently looks like this:
export const MyGCF = functions.https.onRequest((request, response) => {
let dayOfTheWeek: any;
const request1 = require('request');
const url = 'http://worldclockapi.com/api/json/pst/now';
function getDay() {
return new Promise((resolve, reject) => {
request1(url, { json: true }, (err: any, res: any, body: any) => {
if (err) {
return reject(err);
}
resolve(body.dayOfTheWeek);
});
});
}
getDay().then((data) => {
dayOfTheWeek = data;
console.log(dayOfTheWeek);
});
});
In general your approach will work, and you can define additional functions inside of your MyGCF handler, in the same way that you have defined getDay(). One problem with you current code however is that you're forgetting to "write a response" for the request being processed by MyGCF.
You can write a response for the request by calling send() on the second res argument of your MyGCF request handler. A simple example would be:
/* Sends a response of "hello" for the request */
res.send("hello");
With respect to your code, you can use res.send() in your .then() callback to send a response back to the client after getDay() has completed (see code below). Note also to include a .catch() clause and callback for the error case (with an error status) to ensure the client receives an appropriate error response if the call to getDay() fails:
export const MyGCF = functions.https.onRequest((req, res) => {
const request = require('request');
const url = 'http://worldclockapi.com/api/json/pst/now';
function getDay() {
return new Promise((resolve, reject) => {
request(url, {
json: true
}, (err: any, r: any, body: any) => {
if (err) {
reject(err);
} else {
resolve(body.dayOfTheWeek);
}
});
});
}
getDay().then((dayOfTheWeek) => {
/* Send a response once the getDay() request complete */
res.send(dayOfTheWeek);
})
.catch(err => {
/* Don't forget the error case */
res.status(500).send(err);
});
});

await returning undefined when i call async function?

So in main.ts i am trying to call class method processResponse to get the data back from handler but it always return custObject undefined its nor even stepping into processResponse function , what is implemented wrong in below code ?
main.ts
private async custResponse(data: any): Promise < any > {
const custObject = await RequestResponseHandler.processResponse(data);
return custObject;
}
handler.ts
public static async processResponse(data: any): Promise<any> {
let response: any = {};
console.log("Data>>..>>>>", data); // undefined
try {
if (data.Header.StatusCode === "0000") {
response = data.Details;
const tokenId = await this.cacheResponse(response);
response.Header.tokenID = tokenId;
return response;
}
} catch (err) {
return data;
}
}
Since your console.log("Data>>..>>>>", data); is undefined that means the issue is somewhere upstream. You are not passing anything in the data argument to this method. Try checking where you are calling custResponse method and see if the data is actually being passed or not (Its probably not).
As for the undefined return, In your code you are not returning anything if the status code is not OK (In the try block). Try putting some return at the end.
public static async processResponse(data: any): Promise<any> {
//....
//try catch stuff...
//....
return data //or something else
}

How ensure async request has finished before running a function

I am performing an async request to pull data from a server and then call a function after the request. My question is how do I ensure the request is complete and all data loaded before processRecords() runs?
Thanks in advance.
function getRecords () {
var ids = Server.getIds();
var allTheRecords = [];
ids.forEach(function(recordId) {
Server.getRecord(recordId, function (error, data) {
if(error) {
console.log(error);
} else {
allTheRecords.push(data);
};
});
});
processRecords(allTheRecords);
}
How are you performing the Asynchronous request? If it's an AJAX request, the API provides for callbacks to be supplied based on the result of the call.
https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
You could use the native Promise api to perform the async actions for you.
Using Promise.all you can give it an array of promises that need to be resolved before calling the processRecords function.
It also now more reusable as you have a getRecord function that you could use elsewhere in your code.
You should probably think of a way to add in the ability to get multiple records from the server if you control it though. You don't really want to fire off a bunch of network requests if you can do it in just one.
// Server mock of the api you have shown
const Server = {
getRecord(id, callback) {
console.log('getRecord', id)
callback(null, {id})
},
getIds() {
return [1, 2, 3]
}
}
function getRecords (ids, processRecords) {
console.log('getRecords', ids.join())
// mapping the array of id's will convert them to an
// array of Promises by calling getRecord with the id
Promise.all(ids.map(getRecord))
// then is called once all the promises are resolved
.then(processRecords)
// this will be called if the reject function of any
// promise is called
.catch(console.error.bind(console))
}
function getRecord(recordId) {
// this function returns a Promise that wraps your
// server call
return new Promise((resolve, reject) => {
Server.getRecord(recordId, function (error, data) {
if(error) {
reject(error)
} else {
resolve(data)
}
})
})
}
getRecords(Server.getIds(), function(records) {
console.log('resolved all promises')
console.log(records)
})

JS promise passing between functions / wait for promises

I am trying to work through JS Promises in node.js and don't get the solution for passing promises between different function.
The task
For a main logic, I need to get a json object of items from a REST API. The API handling itself is located in a api.js file.
The request to the API inthere is made through the request-promise module. I have a private makeRequest function and public helper functions, like API.getItems().
The main logic in index.js needs to wait for the API function until it can be executed.
Questions
The promise passing kind of works, but I am not sure if this is more than a coincidence. Is it correct to return a Promise which returns the responses in makeRequest?
Do I really need all the promises to make the main logic work only after waiting for the items to be setup? Is there a simpler way?
I still need to figure out, how to best handle errors from a) the makeRequest and b) the getItems functions. What's the best practice with Promises therefor? Passing Error objects?
Here is the Code that I came up with right now:
// index.js
var API = require('./lib/api');
var items;
function mainLogic() {
if (items instanceof Error) {
console.log("No items present. Stopping main logic.");
return;
}
// ... do something with items
}
API.getItems().then(function (response) {
if (response) {
console.log(response);
items = response;
mainLogic();
}
}, function (err) {
console.log(err);
});
api.js
// ./lib/api.js
var request = require('request-promise');
// constructor
var API = function () {
var api = this;
api.endpoint = "https://api.example.com/v1";
//...
};
API.prototype.getItems = function () {
var api = this;
var endpoint = '/items';
return new Promise(function (resolve, reject) {
var request = makeRequest(api, endpoint).then(function (response) {
if (200 === response.statusCode) {
resolve(response.body.items);
}
}, function (err) {
reject(false);
});
});
};
function makeRequest(api, endpoint) {
var url = api.endpoint + endpoint;
var options = {
method: 'GET',
uri: url,
body: {},
headers: {},
simple: false,
resolveWithFullResponse: true,
json: true
};
return request(options)
.then(function (response) {
console.log(response.body);
return response;
})
.catch(function (err) {
return Error(err);
});
}
module.exports = new API();
Some more background:
At first I started to make API request with the request module, that works with callbacks. Since these were called async, the items never made it to the main logic and I used to handle it with Promises.
You are missing two things here:
That you can chain promises directly and
the way promise error handling works.
You can change the return statement in makeRequest() to:
return request(options);
Since makeRequest() returns a promise, you can reuse it in getItems() and you don't have to create a new promise explicitly. The .then() function already does this for you:
return makeRequest(api, endpoint)
.then(function (response) {
if (200 === response.statusCode) {
return response.body.items;
}
else {
// throw an exception or call Promise.reject() with a proper error
}
});
If the promise returned by makeRequest() was rejected and you don't handle rejection -- like in the above code --, the promise returned by .then() will also be rejected. You can compare the behaviour to exceptions. If you don't catch one, it bubbles up the callstack.
Finally, in index.js you should use getItems() like this:
API.getItems().then(function (response) {
// Here you are sure that everything worked. No additional checks required.
// Whatever you want to do with the response, do it here.
// Don't assign response to another variable outside of this scope.
// If processing the response is complex, rather pass it to another
// function directly.
}, function (err) {
// handle the error
});
I recommend this blog post to better understand the concept of promises:
https://blog.domenic.me/youre-missing-the-point-of-promises/

Categories