Dynamically call getJSON inside $.when block - javascript

Is there some way to rewrite this in less lines of code, by making it dynamic instead of doing multiple similar calls with different indexes?
var input = getInput();
var URL = getEndpointURL();
var results = [];
$.when(
$.getJSON(URL+input[0], function (data,status) {
results[0] = data;
}),
$.getJSON(URL+input[1], function (data,status) {
results[1] = data;
}),
$.getJSON(URL+input[2], function (data,status) {
results[2] = data;
}),
$.getJSON(URL+input[3], function (data,status) {
results[3] = data;
}),
$.getJSON(URL+input[4], function (data,status) {
results[4] = data;
}),
).then(function() {
processResults(results);
});

Assuming input is an array you can map() the array to request promises and use Promise.all() on that array.
const URL = 'https://jsonplaceholder.typicode.com/todos/',
input = [3, 5, 6];
const requestPromises = input.map(function(inp) {
return $.getJSON(URL + inp);
});
Promise.all(requestPromises).then(processResults)
function processResults(data) {
console.log(data)
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>

Related

javascript - working with multiple promises inside loop - how to return data outside of promise?

I'm struggling to understand how I can return data from multiple promises to build up an array of data.
Is there anyway I can return the data outside of the promise to push to the data variable?
I have the following:
db_sh.find({
selector: {sh: req.params.sh_id},
fields: ['_id', 'sh_id', 'time'],
sort: ['_id']
}).then(function (result) {
let data = {};
console.log('Found: ' + result.docs.length);
if (result.docs.length > 0) {
for (var i = 0; i < result.docs.length; i++) {
let student = result.docs[i];
Promise
.all([getMealBooking(student._id), getStudentData(student._id)])
.then(function(response) {
var meal_booking_data = response[0];
var student_data = response[1];
console.log(meal_booking_data);
console.log(student_data);
})
.catch(function (err) {
return res.send(false);
});
data[student.time] = [
meal_booking_data,
student_data
]
}
}
/** Sort Data Oldest First*/
data = Object.keys(data).sort().reduce((a, c) => (a[c] = data[c], a), {});
console.log(data);
res.send(data);
});
I have two promises (getMealBooking() & getStudentData()): and I am using Promise.all() to return me the results of both of these promises. I have tried to return the data but I cannot get the results to build up the data array.
Any help to be able to build up a list of all my data would be great.
You need two Promise.alls - one to iterate over each student, and a nested one to fetch the getMealBooking and getStudentData for each student.
Put everything into an async function (that catches and sends false if needed) to make the control flow easier to understand.
const { docs } = await db_sh.find({
selector: { sh: req.params.sh_id },
fields: ['_id', 'sh_id', 'time'],
sort: ['_id']
});
if (docs.length === 0) {
// no data; stop here
res.send({});
return;
};
const data = {};
await Promise.all(
docs.map(student => (
Promise.all([getMealBooking(student._id), getStudentData(student._id)])
.then(([mealBookingData, studentData]) => {
data[student.time] = [mealBookingData, studentData];
})
))
);
const sortedData = Object.keys(data).sort().reduce((a, c) => (a[c] = data[c], a), {});
res.send(sortedData);
Another Promise.all() is needed for the loop that contains the Promise.all() you've already figured out. It's better to factor a little so you can see what's happening.
function getStudentMealAndData(student) {
return Promise
.all([getMealBooking(student._id), getStudentData(student._id)])
.then(function(response) {
var meal_booking_data = response[0];
var student_data = response[1];
console.log(meal_booking_data);
console.log(student_data);
return { student, meal_booking_data, student_data };
})
.catch(function (err) {
return res.send(false);
});
}
This simplifies the then block a bit...
}).then(function (result) {
console.log('Found: ' + result.docs.length);
let promises = []
for (var i = 0; i < result.docs.length; i++) {
let student = result.docs[i];
promises.push(getStudentMealAndData(student));
}
return Promise.all(promises);
}).then(results => {
// results are an array of [{ student, meal_booking_data, student_data }, ...]
let data = results.reduce((acc, s) => {
acc[s.student.time] = [ s.meal_booking_data, s.student_data ];
return acc;
}, {});
data = Object.keys(data).sort().reduce((a, c) => (a[c] = data[c], a), {});
console.log(data);
res.send(data);
});
let arr = [];
const datas = await Promise.all([
getMealBooking(),
getStudentData()
]);
arr.push(datas[0]); //adds getMealBooking() results
arr.push(datas[1]); // adds getStudentData() results

How to wait for multiple API calls to reutrn?

I have an array of APIs to query. For example var urls = ['example.org?x=1', 'example.org?x=2,3'] How can I have ReactJS wait for all the responses (which are JSON) to come back before responding to the client?
I've tried a modification #Shanoor's answer from Promises with http.get node.js but the result to the client is empty ("").
var http = require('http');
var urls = ['example.org', 'example2.org', '...'];
var done = 0;
var result = [];
function callback(index, data) {
result[index] = data;
done++;
if (done == urls.length) {
result.forEach(console.log);
//I tried using the resp object here to return result[] but the data seemed corrupt
}
}
function processUrl(url, index) {
var finalData = '';
http.get(url, function(response) {
response.setEncoding('utf8');
response.on('data', function(data) {
finalData += data;
});
response.on('error', console.error);
response.on('end', function() {
callback(index, finalData);
})
});
}
app.get("/api/blah", (resp) => {
urls.forEach(processUrl);
//resp(result); this would result in an empty response
}
You can use Promise to do that, should be something like
function processUrl(url, index) {
var finalData = '';
return new Promise((resolve, reject) => {
http.get(url, function(response) {
response.setEncoding('utf8');
response.on('data', function(data) {
finalData += data;
});
response.on('error', reject);
response.on('end', function() {
resolve(finalData);
})
});
})
}
app.get("/api/blah", (resp) => {
Promise.all(urls.map(processUrl)).then(function(results) {
console.log(results);
});
}
Note that I didn't checked if the code is working, so please read more about Promises and the Promise.all() method

Request result from async function

I need the value of the variable 'result' to make a comparison. Im having problem to get this 'result' value.
Does anyone know how to fix it?
**Im using node to make an REST application, and I need this to result in my GET method
async function get(req, res, next) {
var result = 0;
try {
const context = {};
const login = {};
login.user = req.params.user, 100;
login.pass = req.params.pass, 200;
var optionsgetmsg = {
host: 'URL', // here only the domain name
// (no http/https !)
path: '/controller/verifica.asp?a=' + login.user + '&b=' + login.pass, // the rest of the url with parameters if needed
method: 'GET' // do GET
};
var reqGet = https.request(optionsgetmsg, function (res) {
res.on('data', function (d) {
jsonResponse = JSON.parse(d);
result = jsonResponse.message;
});
});
reqGet.end();
reqGet.on('error', function (e) {
console.error(e);
});
context.id = parseInt(req.params.id, 10);
console.log(result);
//problem
if(result == "yes"){
const rows = await operadores.find(context);
if (req.params.id) {
if (rows.length === 1) {
res.status(200).json(rows[0]);
} else {
res.status(404).end();
}
} else {
res.status(200).json(rows);
}
}
}
You can use a library that does HTTP requests and supports promises, something like axios or refactor your current https.request and convert it to a promise, here is an example:
function makeRequest({ user, password }) {
return new Promise((resolve, reject) => {
const options = {
host: 'URL',
path: `/controller/verifica.asp?a=${encodeURIComponent(user)}&b=${encodeURIComponent(pass)}`
method: 'GET'
};
const reqGet = https.request(options, function (res) {
res.on('data', function (d) {
result = JSON.parse(d);
resolve(result.message);
});
});
reqGet.on('error', function (e) {
reject(e);
});
reqGet.end();
});
}
Then you can simply do this:
const result = await makeRequest(req.params);
I've used some concepts that you may not be familiar with, template literal and object
destructuring

Bookshelfjs multiple update data not return promise

I want to update multiple row to my database. My problem is the promise not return anything. It save successfully but not return anything.
Here sample of my code:
doUpdate: Promise.method(function (data) {
var self = this;
var jsonData = JSON.parse(data);
return Bookshelf.transaction(function (t) {
return _.each(jsonData, function (value, key) {
var queryMatch = {
id: value.id,
id2: value.id2
};
return self.forge(queryMatch)
.fetch({transacting: t})
.then(function (data) {
return data.save({content: value.newValue});
})
.catch(function(error) {
console.log(error)
})
});
});
})
I'm using bluebird promise.
I tried to keep my code as close to yours as possible. I did manage to do what you asked, so take a look if that's something you can use.
doUpdate: Promise.method(function(data) {
var Self = this;
var jsonData = JSON.parse(data);
return bookshelf.transaction(function(t) {
return Promise.each(jsonData, function(value, key) {
var queryMatch = {
id: value.id,
id2: value.id2
};
return new Self(queryMatch).save({
content: value.newValue
}, {
transacting: t,
method: 'update'
});
});
});
})
Let me know if this works for you.

Parse Promise 'when' returns undefined (Javascript)

I'm trying to follow the 'when' example on Parse JavaScript SDK: Parse.Promise
with the following code:
GetFromDB2 = function(id) {
var DB2 = Parse.Object.extend("DB2");
var q = new Parse.Query(DB2);
q.get(id, {
success: function(res) {
return Parse.Promise.as(10);
},
error: function(res, err) {
console.log( err);
}
});
}
GetData = function() {
var DB1 = Parse.Object.extend("DB1");
var query = new Parse.Query(DB1);
query.equalTo("param", "close");
query.find().then(function(results) {
var promises = [];
_.each(results, function(res) {
promises.push(GetFromDB2(res.get("user")));
});
Parse.Promise.when(promises).then(function() {
console.log(arguments); // expect: [10, 10, ...]
})
});
};
The length of the array arguments is correct but not sure why its values are undefined.
As written, GetFromDB2() returns undefined. To deliver a value, it must return either a value or a promise.
At its simplest, to deliver 10, you could write :
function GetFromDB2(id) {
return 10;
}
But to be asynchronous, and still deliver 10, you need to return a promise that will resolve to 10 :
function GetFromDB2(id) {
return Parse.Promise.as(10);
}
Or the .get(id) query you really want :
function GetFromDB2(id) {
var DB2 = Parse.Object.extend('DB2');
var q = new Parse.Query(DB2);
return q.get(id).then(function(res) {
return 10;
});
//omit `.then(...)` entirely to deliver `res`
}
Now GetData() can be written as follows :
function GetData() {
var DB1 = Parse.Object.extend('DB1');
var query = new Parse.Query(DB1);
query.equalTo('param', 'close');
return query.find().then(function(results) {
var promises = _.map(results, function(res) {
return GetFromDB2(res.get('user'));
});
Parse.Promise.when(promises).then(function() {
console.log(arguments); // expect: [10, 10, ...]
}, function(err) {
console.log(err);
return err;
});
});
};
Notes:
promises = _.map(...) is more elegant than _.each(...) plus `promises.push(...).
moving the error handler into GetData() allows a greater range of possible errors to be handled, eg an error arising from query.find().
By returning a promise, GetData()'s caller is also informed of the eventual asynchronous outcome.

Categories

Resources