How can I run this function synchronously in node.js [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 years ago.
I want to run the function synchronously. In my application
the supply source needs to be created before it is assigned to the other data.
And the application should only further if this task was fulfilled.
Because otherwise it will fail because the other data is created and no SupplySourceId is found (undefinded).
here i want to start the synchronous function (processSupplySource();)
var articleSupplySourceId = processSupplySource();
Function ProcessSupplySource:
function processSupplySource(){
var postJson2 = {};
postJson2.articleNumber = entry['part-no'];
postJson2.name = entry['part-no'];
postJson2.taxName = 'Vorsteuer';
postJson2.unitName = 'stk';
postJson2.supplierNumber = "1002";
postJson2.articlePrices = [];
var articlePrices = {};
articlePrices.currencyName = 'GBP';
articlePrices.price = entry['ek-preisgbp'];
articlePrices.priceScaleType = 'SCALE_FROM';
articlePrices.priceScaleValue = '1';
postJson2.articlePrices.push(articlePrices);
return postSupplySource(postJson2);
Function PostSupplySource
function postSupplySource(postJson2) {
rp({
method: 'POST',
url: url + '/webapp/api/v1/articleSupplySource',
auth: {
user: '*',
password: pwd
},
body: postJson2,
json: true
}).then(function (parsedBody) {
console.log('FinishArticleSupplySource');
var r1 = JSON.parse(parsedBody);
console.log(r1.id);
return r1.id;
})
.catch(function (err) {
console.log('errArticleSupplySource');
console.log(err.error);
// POST failed...
});
}

You can use async/await if you are using node 8 to get that synchronous behaviour you looking for.
Otherwise, you will need to use a library like deasync to wait for the post to complete and return the id.

You can wrap your postSupplySource function in a promise and call the other function when it resolves. This will ensure you have `sourceSupplyId' by the time you run the other functions. Except in case of an error. Something like this:
function postSupplySource(postJson2) {
return new Promise(resolve, reject){ //**added
rp({
method: 'POST',
url: url + '/webapp/api/v1/articleSupplySource',
auth: {
user: '*',
password: pwd
},
body: postJson2,
json: true
}).then(function (parsedBody) {
console.log('FinishArticleSupplySource');
var r1 = JSON.parse(parsedBody);
console.log(r1.id);
resolve(r1.id); // ** added
})
.catch(function (err) {
console.log('errArticleSupplySource');
console.log(err.error);
return reject(err); //*** added
// POST failed...
});
});
}
And then you can call the other function inside it like this:
postSupplySource(postJson2)
.then((supplySourceId) => {
// supplySourceId is available.
// you can call other functions here.
}).catch((err) => {
console.log(err);
});
Hope I got your question right.
As someone mentioned also, you can use asyc await.
As

Related

synchronous fetch - unexpected results

First of all, I'm aware this is not a good approach, need it as temporary solution for certain functions to return value, not promise. I know it's really not good permanent solution at all, but I need it for now.
What worries me, fetch sure finishes sooner - but it runs until the whiles times out, and then to console comes first the RETVAL false, and only then second line comes RETFETCH: {....} with returned json values - it seems the 'haveResponse' value does not change in the second 'then' - but can't see why, and how to bypass it.
It's a temporary workaround for old sync fns to read some data from remote service running on local pc on some port, but for now I can't rewrite the function which expects to receive data from this fn, so there must be no promise on the outside, need to wait for response and then return it.
function syncFetch(url) {
var haveResponse = false;
var reqtime = new Date();
try{
fetch(url, {
headers: {'Content-Type': 'application/json'},
method: 'POST',
timeout: 1500,
body: JSON.stringify({cmd:'init'})
})
.then(response => response.json())
.then(data => {
console.log('RETFETCH:', data);
haveResponse = data;
return data;
});
// timeout
while (haveResponse === false) {
var endDate = new Date();
if (haveResponse !== false) { return haveResponse; }
if ((endDate - reqtime)/1000 > 5) { // max 5 sec
return haveResponse;
}
}
return haveResponse;
} catch(e){
console.log('error', e);
haveResponse = -1;
}
return haveResponse;
}
console.log('RETVAL',syncFetch('http://127.0.0.1:3333/'));
Save yourself a few headaches, drop all the .then() and use the async/await syntax instead. No need for dirty timeout/while hacks.
I renamed syncFetch to asyncFetch, because your original code was never synchronous in the first place (and that's precisely why you are struggling so much, you believe it is when it's not). async/await don't make the code synchronous either. It's just awesome syntactic sugar around Promises.
(EDIT : you said in the comments that you can't add the async keyword to the parent function (asyncFetch), so here's a workaround to place it inside :
function asyncFetch(url) {
async function a() {
try {
const response = fetch(url, {
headers: { 'Content-Type': 'application/json' },
method: 'POST',
timeout: 1500,
body: JSON.stringify({ cmd: 'init' })
});
const data = await response.json();
return data; // This is a Promise<data>, not data directly, so it needs to be awaited
} catch (e) {
console.log('error', e);
return null
}
};
return a();
};
(async () => {
console.log('RETVAL', await asyncFetch('http://127.0.0.1:3333/')); // Needs to be awaited, and therefore also needs to be inside an async function
})();

Chaining the $http.get AngularJS

As I am making few call to the endpoints within a function and it was causing issue with the parallel calls to the endpoints, so it was suggested in the other question to use the promise chaining. I updated my code so we can call the endpoints one after the other, so the code looks like below
$scope.getRequest = function () {
var url = $rootScope.BaseURL;
var config = {
headers: {
'Authorization': `Basic ${$scope.key}`,
'Prefer': 'odata.maxpagesize=2000'
}
};
$http.get(url, config)
.then(newViewRequest)
.then(function(response){
$scope.viewRequest.data = response.data;
},
function (response) { // failure async
console.log("There was an error getting the request from CORE");});
};
var newViewRequest = function (response) {
var url1 = $rootScope.BaseURL + `CMQ_REQUEST('${$scope.viewRequest.barcode}')`;
if (response.data.REV_SAMPLE_CMQREQUEST.length = 0) {
return $http.get(url1, config)
}
return $q.reject({ message: 'Validations didnt work' });
};
It always sends the reject message back from the newViewRequest if response.data.REV_SAMPLE_CMQREQUEST.length = 0, if I comment it out I get the response.data is undefined.
Update your condition to validate instead of assigning
Issue: Update if condition as below to check response.data.REV_SAMPLE_CMQREQUEST.length whether it is 0 or not with === instead of =
if (response.data.REV_SAMPLE_CMQREQUEST.length === 0)

Javascript: Promise returning instantly, rather than waiting for asynchronous process to finish

Essentially when i call my function getToken() it should return the bearer + token from the api.
The problem I have is that due to the asynchronous process that happens, the data is not returned instantly; so in reading the following resource:
How do I return the response from an asynchronous call?
My understanding is that I need to return my response in the form of a promise, and set a timeout to ensure that the return accounts for the time it takes for the server to send back my request in the form of a response.
var request = require('request-promise');
var time = require('timers');
class Auth {
getToken() {
let options = {
method: 'POST',
uri: 'https://example.com/service/ep',
body: {
username: 'someUser',
password: 'somePass'
},
json: true
}
request(options)
.then(function (body) {
// console.log(body)
return new Promise((resolve) => {
time.setTimeout(() => {
resolve(body)
},3000)
});
})
.catch(function (err) {
return err
});
}
}
module.exports = new Auth
Unfortunately when i run my program in the node repel, it returns nothing and it does not appear to wait; of course when i log my response 'console.log(body)', it appears meaning there must be something wrong with how i'm returning my promise; i'm quite new to the likes of promises.
Could use with a second pair of eyes.
My understanding is that I need to return my response in the form of a promise, and set a timeout to ensure that the return accounts for the time it takes for the server to send back my request in the form of a response.
No. You need to return a promise (request already gives you one) and then the code you return the promise to needs to expect a promise (and call then() on it to get the data).
You don't need any time delays.
var request = require('request-promise');
var time = require('timers');
class Auth {
getToken() {
let options = {
method: 'POST',
uri: 'https://example.com/service/ep',
body: {
username: 'someUser',
password: 'somePass'
},
json: true
}
return request(options);
}
}
module.exports = new Auth
const auth = require("Auth");
auth.getToken().then(function (data) {
console.log(data);
});

NodeJS - loop with nested API calls

Hello I'm new to NodeJs and am trying to work out the best way to get this chain of events working. I have to do two API calls get all the information I need. The first API call is just a list of IDs, then the second API call I pass the ID to get the rest of the information for each object.
However using the method below, I have no idea when everything is finished. Please can someone help me out.
function getData() {
var options = {
method: 'GET',
uri: 'https://api.call1.com',
qs: {
access_token: _accessToken,
}
};
request(options).then(function(apires){
console.log("complete 1");
var obj = JSON.parse(apires);
obj.data.forEach(function(entry) {
findMore(entry.id)
});
})
}
function findMore(id) {
var options = {
method: 'GET',
uri: 'https://api.call2.com',
qs: {
access_token: _accessToken,
}
};
request(options).then(function(apires){
console.log("complete 2");
var obj = JSON.parse(apires);
})
}
You can make your findMore method return a promise, so you can pass an array of those to Promise.all and handle the .then when all promises have finished.
function getData() {
var options = {
method: 'GET',
uri: 'https://api.call1.com',
qs: {
access_token: _accessToken,
}
};
request(options).then(function(apires){
console.log("complete 1");
var obj = JSON.parse(apires);
var promises = [];
obj.data.forEach(function(entry) {
promises.push(findMore(entry.id));
});
return Promise.all(promises);
})
.then(function (response) {
// Here response is an array with all the responses
// from your calls to findMore
})
}
function findMore(id) {
var options = {
method: 'GET',
uri: 'https://api.call2.com',
qs: {
access_token: _accessToken,
}
};
return request(options);
}
A couple of things to think about:
If you care about the fate of a promise, always return it.
In your case, findMore does not return the promise from request, so getData has no handle to track the resolution (or rejection) of that promise.
You can track the resolution of multiple promises with Promise.all.
The Promise.all() method returns a single Promise that resolves when all of the promises in the iterable argument have resolved or when the iterable argument contains no promises. It rejects with the reason of the first promise that rejects.
Lets put these to use on your example:
function getData() {
var options = {
method: 'GET',
uri: 'https://api.call1.com',
qs: {
access_token: _accessToken,
}
};
return request(options)
.then(function(apires){
var obj = JSON.parse(apires);
var findMorePromises = obj.data.map(function(entry) {
return findMore(entry.id)
});
return Promise.all(findMorePromises);
})
}
function findMore(id) {
var options = {
method: 'GET',
uri: 'https://api.call2.com',
qs: {
access_token: _accessToken,
}
};
return request(options)
.then(function(apires){
return JSON.parse(apires);
})
}
I've used map to construct the array of promises, but you could just as well use a foreach and push into an array similar to be more similar to your example code.
It's also good practice to make sure you are handling rejection of any promises (via catch), but I'll assume that is out of the scope of this question.
You want to use Promise.all.
So first thing first, you need an array of promises. Inside your for each loop, set findMore to a variable, and make it return the promise. Then have a line where you do Promise.all(promiseArr).then(function(){console.log("done)})
Your code would look like this
function getData() {
var promiseArr = []
var options = {
method: 'GET',
uri: 'https://api.call1.com',
qs: {
access_token: _accessToken,
}
};
request(options).then(function(apires){
console.log("complete 1");
var obj = JSON.parse(apires);
obj.data.forEach(function(entry) {
var p = findMore(entry.id)
promiseArr.push(p)
});
}).then(function(){
Promise.all(promiseArr).then(function(){
console.log("this is all done")
})
})
}
function findMore(id) {
var options = {
method: 'GET',
uri: 'https://api.call2.com',
qs: {
access_token: _accessToken,
}
};
return request(options).then(function(apires){
console.log("complete 2");
var obj = JSON.parse(apires);
})
}
the basic idea of Promise.all is that it only executes once all promises in the array have been resolved, or when any of the promises fail. You can read more about it here
You need to use Promise.all to run all async requests in parallel. Also you must return the result of findMore and getData (they are promises).
function getData() {
var options = {...};
return request(options)
.then(function(apires) {
console.log("complete 1");
var obj = JSON.parse(apires);
var ops = obj.data.map(function(entry) {
return findMore(entry.id);
});
return Promise.all(ops);
}
function findMore(id) {
var options = {...};
return request(options)
.then(function(apires) {
console.log("complete 2");
return JSON.parse(apires);
});
}
getData()
.then(data => console.log(data))
.catch(err => console.log(err));
If you can use ES7, it can be written with async/await:
let getData = async () => {
let options = {...};
let res = awit request(options);
let ops = res.data.map(entry => findMore(entry.id));
let data = await Promise.all(ops);
return data;
};
let findMore = async (id) => {
let options = {...};
let apires = awit request(options);
return JSON.parse(apires);
};
EDIT: As others have mentioned, using a Promise.all() is likely a better solution in this case.
If you are open to using jQuery (a JavaScript library), then you can use the .ajaxStop() event handler and specify your own function. Sample code:
$(document).ajaxStop(function(){
alert("All AJAX requests are completed.");
});
You will need to include the jQuery module. The instructions for Node.js are:
Install module through npm:
npm install jquery
Then use a "require" to use jQuery in your JavaScript code (a window with a document is required but there is no such "window" in Node so you can mock one with jsdom), see npm - jQuery for details:
require("jsdom").env("", function(err, window) {
if (err) {
console.error(err);
return;
}
var $ = require("jquery")(window);
});
If you want to stick to a pure JavaScript approach, you will need to create your own "module" to keep track of AJAX requests. In this module you can keep track of how many pending requests there are and remove them once they are terminated. Please see: Check when all Ajax Requests are complete - Pure JavaScript for more details.

Multiple promise requests chained together in Javascript

I am attempting to chain together multiple asynchronous requests in JS. Basically, I want to retrieve the artist info from the LastFM API, then using that info lookup their top tracks.
So far, I can successfully get the artists info, have it return, and it prints out the info in the next step. However, once I try to do my second request for the top tracks, the body is never printed and it immediately moves on to the next step.
I have tried many many different combinations of this code with different kinds of requests and such but I haven't gotten any luck. I just want to successfully do request 1 if successful then follow it up by others in a proper order.
var artistInfo = {
method: 'GET',
url: 'http://localhost:3000/users/db/artistInfo/' + artistName
};
var topTracks = { method: 'GET',
url: 'http://localhost:3000/users/db/topTracks/' + artistName
};
/* Dependencies */
var Promise = require('bluebird');
var reqP = Promise.promisifyAll(require('request-promise'));
reqP(artistInfo)
.then(function(info) {
console.log("got here 1");
return info;
})
.then(function(artist) {
console.log(artist);
reqP(topTracks)
.then(function(body) {
console.log(body);
console.log("got here 2");
return body;
});
return 'test';
})
.then(function(content) {
console.log(content);
return 'test2';
})
.catch(function(err) {
throw err;
});
To sequence these two requests and have the outer .then() wait for both, you need to return the internal promise (the one inside the .then() handler) in order to chain them. If you don't return them, then then nothing is chained to the parent promise and therefore the parent promise doesn't wait for the child promise. See the line where I added return to return reqP(topTracks):
var artistInfo = {
method: 'GET',
url: 'http://localhost:3000/users/db/artistInfo/' + artistName
};
var topTracks = { method: 'GET',
url: 'http://localhost:3000/users/db/topTracks/' + artistName
};
/* Dependencies */
var Promise = require('bluebird');
var reqP = Promise.promisifyAll(require('request-promise'));
reqP(artistInfo)
.then(function(info) {
console.log("got here 1");
return info;
})
.then(function(artist) {
console.log(artist);
// *** add return here ***
return reqP(topTracks)
.then(function(body) {
console.log(body);
console.log("got here 2");
return body;
});
})
.then(function(content) {
console.log(content);
return 'test2';
})
.catch(function(err) {
throw err;
});
FYI, it doesn't look like your two requests depend upon one another so you could also do them in parallel:
var artistInfo = {
method: 'GET',
url: 'http://localhost:3000/users/db/artistInfo/' + artistName
};
var topTracks = { method: 'GET',
url: 'http://localhost:3000/users/db/topTracks/' + artistName
};
/* Dependencies */
var Promise = require('bluebird');
var reqP = Promise.promisifyAll(require('request-promise'));
Promise.all([reqP(artistInfo), reqP(topTracks)]).then(function(results){
// results[0] is artist
// results[1] is tracks
}, function(err){
// error here
});
First, I don't know why you are promisifying a promise-based library. There are a couple of ways to do this, but I am going to give you what I think is the cleanest way, but it requires bluebird (which you are using in your example anyway, so shouldn't be a problem)
It doesn't look like your second request depends on your first, you can use Promise.props()
/* Dependencies */
var Promise = require('bluebird');
var request = require('request-promise');
var artistInfo = request({
method: 'GET',
url: 'http://localhost:3000/users/db/artistInfo/' + artistName
});
var topTracks = request({
method: 'GET',
url: 'http://localhost:3000/users/db/topTracks/' + artistName
});
Promise.props({
artistInfo: artistInfo,
topTracks: topTracks
}).then(function(result) {
console.log(JSON.stringify(result.artistInfo,null,2));
console.log(JSON.stringify(result.topTracks,null,2));
})
.catch(function(err) {
console.error(err);
});
So what is going on here? Promise.props allows you to pass an object whose properties are promises. These promises will then execute in parallel and the promise won't be resolved until both are resolved (or it will drop to catch if either fail).
As for chaining promises, you need to make sure to return a promise. This is what allows you to avoid the ugly nesting
/* Dependencies */
var Promise = require('bluebird');
var request = require('request-promise');
request({
method: 'GET',
url: 'http://localhost:3000/users/db/artistInfo/' + artistName
})
.then(function(artistInfo) {
console.log(artistInfo);
return request({
method: 'GET',
url: 'http://localhost:3000/users/db/topTracks/' + artistName
});
})
.then(function(topTracks) {
console.log(topTracks);
})
.catch(function(err) {
console.error(err);
});

Categories

Resources