Call a functions inside a function already call - javascript

I'm trying to understand how to use function.
I have 2 functions inside the file functions.js:
getAllIssueForSCII()
test()
I have a another file (index.js) for call function but got some problem for call the function test().
functions.js
function getAllIssueForSCII(){
var options = {
...
};
return new Promise(function (resolve) {
request(options, function (error, response, data) {
if (!error && response.statusCode === 200) {
console.log('JIRA login success!!')
var json = JSON.parse(data);
resolve(json);
} else {
console.log('error: ' + response.statusCode + ': ' + data.statusMessage)
}
})
})
}
function test(){
/* We recover the value of the priority and we give it a score according to its value */
var priority = json.issues[i].fields.priority.name;
var score1 = 0 ;
switch (priority){
...
}
}
index.js
var functions = require('./functions.js')
functions.getAllIssueForSCII().then(function(json){
for (var i=0; i<json.issues.length;i++){
console.log(json.issues[i].key);
functions.test(); //Error
}
});

Related

Making promise wait for another promise

Within a node.js app, I'm trying to look up a list of products from an API, then get the thumbnail image for the first item only.
Within my code getOrderDetails is a promise, and then if it's the first product, it calls function getImage which is also a promise.
However when I run the code the orderDetails is populated without the thumbnail - so it looks like the code isn't waiting for the getImage function to resolve.
Please can someone explain what I have done wrong?
Thank you in advance!
if (siteConfig.storeIntegration == 'Cart') {
getOrderDetails(restPathOrder)
.then(function(res) {
var orderDetails = '';
for (i = 0; i < res.items.length; i++) {
productId = res.items[i]['productId'];
thumbnail = '';
if (i == 0) {
getImage(productId, restApiKey)
.then(function(res) {
thumbnail = res;
console.log('thumbnail:' + res);
})
}
orderDetails = orderDetails + res.items[i]['quantity'] + ',' + res.items[i]['name'] + ',' + productUrl + ',' + thumbnail;
}
console.log(orderDetails);
})
}
function getOrderDetails(restPath) {
return new Promise((resolve, reject) => {
request(restPath, function (error, response, body) {
if (!error && response.statusCode == 200) {
restData = JSON.parse(body);
resolve(restData)
}
})
})
}
function getImage(productId, restApiKey) {
return new Promise((resolve, reject) => {
var restPathProduct = storeURL + restApiKey + productId;
request(restPathProduct, function (error, response, body) {
if (!error && response.statusCode == 200) {
restData = JSON.parse(body);
thumbnail = restData.image[0];
resolve(thumbnail);
}
})
})
}
Might I suggest using new await syntax?
async main() {
if (siteConfig.storeIntegration == 'Cart') {
let res = await getOrderDetails(restPathOrder);
var orderDetails = '';
for (i = 0; i < res.items.length; i++) {
productId = res.items[i]['productId'];
let thumbnail = '';
if (i == 0) {
thumbnail = await getImage(productId, restApiKey);
}
orderDetails += res.items[i]['quantity'] + ',' + res.items[i]['name'] + ',' + productUrl + ',' + thumbnail;
}
console.log(orderDetails);
}
}
#FrankerZ is right that async/await makes the code much cleaner.
I'm unsure on your business logic, where productUrl comes from.
The solution is to wrap the whole block of code in a promise, get the image for the first order, and in the then of getImage, then you can process the order details.
Here is my attempt, with some minor refactors. Hopefully it can steer you in the right direction.
function process() {
// Wrap everything inside a promise, we then resolve with the order details
// Resolve is what gets returned in the .then((resolvedData)), reject is what gets returned in the .catch((rejectedThings))
return new Promise((resolve, reject) => {
// Get the order details
getOrderDetails(restPathOrder)
.then(function(orderRes) {
// Handle no items
if (!orderRes.items || orderRes.items.length === 0) {
return reject("No items") // You can deal with this in the catch
}
// Get first item
const firstOrder = orderRes.items[0];
// Fetch the first thumbnail then proceed to fetch the rest of the order details.
getImage(firstOrder.productId, restApiKey)
.then(function(thumbnail) {
let orderDetails = '';
// Build order details body
// N.B I'm not sure how you want orderDetails to appear, personally I would use a map instead of a forEach.
orderRes.items.forEach((item) => {
orderDetails = orderDetails + item.quantity + ',' + item.name + ',' + productUrl + ',' + thumbnail;
})
// Then resolve with the order details
return resolve(orderDetails);
})
})
})
}
// You can then call process as a promise with the order details
process().then(function(orderDetails) => console.log(orderDetails))

Node request data from API, push data to array. Then run another request using that new array

var UfcAPI = require('ufc-api');
var ufc = new UfcAPI({
version: '3'
});
const fighterId = [];
function getFighterId() {
ufc.fighters(function(err, res) {
for (let i = 0; i < res.body.length; i++) {
fighterId.push(res.body[i].id);
}
// console.log(fighterId);
})
};
function allFighters() {
for (let j = 0; j < fighterId.length; j++) {
request("http://ufc-data-api.ufc.com/api/v3/us/fighters/" + fighterId[j] + ".json", function(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(JSON.parse(body));
}
})
}
};
The first function getFighterId() will look through the json for all fighters on the UFC roster. I capture all Ids of each fighter and push it to the fighterId array. Then i want to do a loop querying fighters with their id to get more detailed info on each fighter.
I understand that I need the array to completely get filled then run my second function. I found info on promises and Async but super confused on how to implement it.
Thanks
var UfcAPI = require('ufc-api');
var ufc = new UfcAPI({
version: '3'
});
function allFighters(fighterIds) {
fighterIds.forEach(fighterId => {
request("http://ufc-data-api.ufc.com/api/v3/us/fighters/" + fighterId + ".json", function(error, response, body) {
if (!error && response.statusCode === 200) {
console.log(JSON.parse(body));
}
})
});
};
function getFighterId(){
return new Promise((resolve,reject)=>{
ufc.fighters((err,res)=>{
if(err) reject(err);
else resolve(res.body)
})
})
}
getFighterId()
.then((ufcData)=>ufcData.map((u)=>u.id))
.then((data)=>allFighters(data))
.catch((err)=>console.log(err));
Please try with this one I have implemented with Promises. it can be implemented in many more ways. Let me know if it helps you.

nodejs pushing to array inside for loop with requests

Starting out with Node without any async knowledge and am wondering how I can push data as part of a callback into an array. The output array is declared but is undefined when its referenced within the request callback. Is there a simple way to just pass that variable into the callback function scope?
Ideally, I'd like to send back an array of the results from each request made back to the caller.
const request = require('request');
module.exports = {
apiRatingCall: function (input, callback) {
var output = []
for (var i = 0; i < input.length; i++) {
var options = {
url: 'someAPIURL' + '?longitude=' + input[i].longitude + '&latitude=' + input[i].latitude + '&name=' + input[i].name,
headers: {
'x-api-version': 2
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
output.push(info) // this is not working as ouput is undefined at this point
}
})
}
callback(output)
}
}
Thanks
my answer maybe not very normative in programming by it is only way for this problem I promise
module.exports = {
apiRatingCall: function (input, callback) {
var output = []
for (var i = 0; i < input.length; i++) {
var options = {
url: 'someAPIURL' + '?longitude=' + input[i].longitude + '&latitude=' + input[i].latitude + '&name=' + input[i].name,
headers: {
'x-api-version': 2
}
};
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
output.push(info) // this is not working as ouput is undefined at this point
}
})
}
setTimeout(function(){
callback(output)
},500)
}
}
You can check the end of for loop and execute your callback
var loopCallback = function(error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
output.push(info)
}
if( i == input.length - 1){ //checking index for completion of loop
callback(output);
}
}
request(options, loopCallback})
Take a look at the async module. It is a good module to do async operation with array and collection if you do not want to use bluebird and promises.
Do npm install async -S.
const request = require('request');
const async = require('async);
module.exports = {
apiRatingCall: function (inputs, callback) {
var output = []
async.each(inputs, function(input, cb) {
var options = {
url: 'someAPIURL' + '?longitude=' + input.longitude + '&latitude=' + input.latitude + '&name=' + input.name,
headers: {
'x-api-version': 2
}
request(options, function (error, response, body) {
if (!error && response.statusCode == 200) {
var info = JSON.parse(body)
output.push(info);
cb();
}else{
//if any of the request fails then return error
cb(error);
}
})
}, function(err){
if(!err){
return callback(output);
}else{
//if any of the request return error
return callback(err);
}
});
}

Concatenate several API request with NodeJS

I'm messing with SteamAPI in order to learn some NodeJS. Right now I'm trying to get games's info after an initial request to get the player's profile, once I have the games IDs stored in an array. The point is that I don't know how to "return" an array AFTER the whole ID array is iterated and all results has come from the server.
function getThumbs(game) {
return rq(
'http://store.steampowered.com/api/appdetails?appids=' + game,
{json: true},
function (error, response, bd) {
if(response.statusCode === 200 && bd[game].data) {
return bd[game].data.screenshots;
}
});
}
function getGamesThumbnails(games) {
var deferred = $q.defer(),
queue = [];
for (var y = 0; y < games.length; y++) {
var game = games[y];
var thumbs = getThumbs(game);
queue.push(thumbs);
}
$q.all(queue).then(
function (data) {
deferred.resolve(data);
},
function (err) {
deferred.reject(err)
}
);
return deferred.promise;
}
app.get('/blog',function(client_req,client_res){
rq('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=' + key + '&steamid=blablabla&format=json', function (error, response, body) {
var data = JSON.parse(body);
var games = data.response.games.map(function (game) {
return game.appid;
});
getGamesThumbnails(games).then(function (data) {
console.log(data)
})
});
});
Basically, you should use a callback, because like you are doing in getThumbsyou are returning the object, while you should return the value bd[game].data.screenshots;
function getThumbs(game, cb) {
return rq(
'http://store.steampowered.com/api/appdetails?appids=' + game,
{json: true},
function (error, response, bd) {
if(response.statusCode === 200 && bd[game].data) {
cb(null, bd[game].data.screenshots);
}
});
}
function getGamesThumbnails(games) {
var deferred = $q.defer(),
queue = [];
for (var y = 0; y < games.length; y++) {
var game = games[y];
getThumbs(game, function(err, value) {
queue.push(value);
});
}
$q.all(queue).then(
function (data) {
deferred.resolve(data);
},
function (err) {
deferred.reject(err)
}
);
return deferred.promise;
}
And plust to return the response to the client you have to use the client_res.send(VALUE)
so the bottom part would become like this:
app.get('/blog',function(client_req,client_res){
rq('http://api.steampowered.com/IPlayerService/GetOwnedGames/v0001/?key=' + key + '&steamid=blablabla&format=json', function (error, response, body) {
var data = JSON.parse(body);
var games = data.response.games.map(function (game) {
return game.appid;
});
getGamesThumbnails(games).then(function (data) {
client_res.send(data);
console.log(data)
})
});
});
Your getThumbs() function does not return a promise. $q.all only works on an array containing promises, whereas rq uses callbacks.
Try this:
function getThumbs(game) {
var deferred = $q.defer(),
rq(
'http://store.steampowered.com/api/appdetails?appids=' + game,
{json: true},
function (error, response, bd) {
if(response.statusCode === 200 && bd[game].data) {
deferred.resolve(bd[game].data.screenshots);
}
});
return deferred.promise;
}
Thank you both!
I tried Yuri's approach, but $q.all it doesn't seem to resolve the array of promises (nothing happens after the last request from getThumbs())
for (var y = 0; y < games.length; y++) {
var game = games[y];
var thumbs = getThumbs(game);
queue.push(thumbs);
}
$q.all(queue).then(
function (data) {
console.log(data)
deferred.resolve(data);
},
function (err) {
deferred.reject(err)
}
);

How to make a proper Node.js error callback?

I'm trying to make a proper asynchronous function which contains a callback but apparently my way of doing this doesn't work.
Here's my code:
var fs = require('fs');
var path = require('path');
var tmp = 0;
var i = 0;
function getFilesByExtArgs(dir, ext, function(err)){
if (err){
console.log("Error: " + err.code + " (" + err.message + ")");
return;
}
else{
fs.readdir(dir, function (err, data){
while (i <= data.length){
if (path.extname(data[i]) == ('.' + ext))
console.log(data[i]);
i++;
}
});
}
}
module.exports = getFilesByExtArgs;
When I try to launch that, I get the following error:
function getFilesByExtArgs(dir, ext, function(err)){
^^^^^^^^
SyntaxError: Unexpected token function
How can I make it "the node way" ?
You just need a parameter for your function and then call it. You can then expect the caller of the function to provide a callback function to that parameter.
Another mistake is your use of the while loop. You're better off if you use a for loop and declare the i variable inside it. That way, you can make sure that no other function will touch the i variable.
Also, instead of i <= data.length you need i < data.length. If you access data[data.length] you will get out of range.
Of course inside the getFilesByExtArgs function you may want to check if the parameter really is a function. You can do it with the typeof operator. For example:
if (typeof(callback) !== "function") {
throw new Error("The callback parameter must be a function");
}
Here's your code, with a fixed syntax:
I assume you want a callback not just for errors, but for actual results as well? Then you can do it like this:
var fs = require('fs');
var path = require('path');
function getFilesByExtArgs (dir, ext, callback) {
if (typeof(callback) !== "function") {
throw new Error("The callback parameter must be a function");
}
fs.readdir(dir, function (err, data) {
if (err) {
return callback(err);
}
var results = [];
for (var i = 0; i < data.length; i++) {
if (path.extname(data[i]) == ('.' + ext)) {
results.push(data[i]);
}
}
callback(null, results);
});
}
You can call it like this:
getFilesByExtArgs('/my/file/path', 'txt', function (err, results) {
if (err) {
// Something bad happened
console.log("an error occoured!");
return;
}
// You can use the results array
console.log("printing the results:");
for (var i = 0; i < results.length; i++) {
console.log(i, results[i]);
}
});
Hope this helps.
You don't define functions as parameters in this way, you simply provide a named parameter which you then invoke as a function e.g.
function getFilesByExtArgs(dir, ext, callback){
if (/* something bad */) {
callback('Error thrown');
} else {
callback();
}
}
...
getFilesByExtArgs('/my/file/path', '.txt', function(err) {
if (err) throw err;
...
});
In your example, I presume what you are trying to do is something like
function getFilesByExtArgs(dir, ext, callback){
fs.readdir(dir, function(err, data) {
if (err) {
callback(err);
} else {
while (i <= data.length) {
if (path.extname(data[i]) == ('.' + ext))
console.log(data[i]);
i++;
}
callback();
}
});
}

Categories