Convert the simple fetch API code to ".then" notation code - javascript

How can I covert following code into .then notation. I wanted to strictly use ".then" notation. That is what I observed with my system.
I raised one question with similar kind of request however, I got the code using async/await. Rather than asking the new requirement over the same thread I initiated this new thread.
Apology for inconvenience. I should have posted this it in first thread itself. Kindly help.
var obj = [{"Id":"10101","descr":"server1.com"},{"Id":"10102","descr":"server2.com"},{"Id":"10103","descr":"server3.com"},{"Id":"10104","descr":"server4.com"},{"Id":"10105","descr":"server5.com"},{"Id":"10106","descr":"server6.com"},{"Id":"10107","descr":"server7.com"}];
var temp = [];
for (var i = 0; i < obj.length; i++){
var id = obj[i].Id;
let response = await fetch('https://abced.com/api/'+id+'/value', {method : "GET", headers: {"Authorization": "xyz"}});
var data = await response.json();
var stats = data.status;
if (stat != "OK")
{
temp.push({Id:obj[i].Id, descr:obj[i].descr, value:"ERROR"})
}
}
console.log(temp);
My expected output is, (values of Id and descr will depends on "if statement" in the code)
[{"Id": "10101","descr": "server1.com","status": "ERROR"},
{"Id": "10103","descr": "server3.com","status": "ERROR"},
{"Id": "10104","descr": "server4.com","status": "ERROR"}]
I tried following but in my system compiler says, "Function declared within loops referencing an outer scope variable mat lead to confusing semantics (Id, descr)"
function fetchMock(url) {
let id = url.split('/')[4];
if ([10101, 10103, 10104].includes(+id)) {
return Promise.resolve({
json() {
return Promise.resolve({
status: 'BAD'
});
}
});
} else {
return Promise.resolve({
json() {
return Promise.resolve({
status: 'OK'
});
}
});
}
}
var obj = [{
"Id": "10101",
"descr": "server1.com"
},
{
"Id": "10102",
"descr": "server2.com"
},
{
"Id": "10103",
"descr": "server3.com"
},
{
"Id": "10104",
"descr": "server4.com"
},
{
"Id": "10105",
"descr": "server5.com"
},
{
"Id": "10106",
"descr": "server6.com"
},
{
"Id": "10107",
"descr": "server7.com"
}
];
function getResults() {
const results = [];
for (let {
Id,
descr
} of obj) {
fetchMock('https://abced.com/api/' + Id + '/value', {
method: "GET",
headers: {
"Authorization": "xyz"
}
}).then(res => res.json()).then(function(data) {
if (data.status !== 'OK') {
results.push({
Id,
descr,
value: 'ERROR'
});
}
});
}
return results;
}
function test() {
const results = getResults();
return results;
}
test();

Related

How to replace multiple async/await calls with Promise.all?

I have the following try/catch block which is making 3 different api calls.
The following code is working fine but it is taking lot of time to execute when firstData has large dataset.
try {
const firstData = await myservice1.myservice1Func();
for(let i=0; i<firstData.total; i++){
const hostName = firstData.rows[i]['hostname'];
if (hostName !== null && firstData.rows[i]['myservice1Id'] !== null) {
const aRes = await myService2(hostName);
firstData.rows[i]['mylist'] =
aRes[0].dataValues;
}
if (hostName !== null && firstData.rows[i]['type'].includes('type1')) {
const oRes = await myService3(hostName);
firstData.rows[i]['ores'] = oRes.rows[0];
}
if (hostName !== null && firstData.rows[i]['type'].includes('type2')) {
const vRes = await myService4(hostName);
firstData.rows[i]['vRes'] = vRes.rows[0];
}
}
return firstData;
} catch (err) {
console.log(err);
}
Here,
const firstData =
{
"total": 2,
"rows": [
{
"hostname": "abc.com",
"ipAddress": "11.11.11.11",
"myservice1Id": "ee0f77c9-ef15",
"type": "type1"
},
{
"hostname": "cde.com",
"ipAddress": "12.12.12.12",
"type": "type2",
"myservice1Id": null
}
]
}
const aRes =
[
{
"listType": "list1",
"createdAt": "2020-12-07"
}
]
const oRes =
{
"rows": [
{
"status": "FAIL"
}
]
}
const vRes =
{
"rows": [
{
"status": "FAIL"
}
]
}
The final value of firstData returned is as following:
{
"total": 2,
"rows": [
{
"hostname": "abc.com",
"ipAddress": "11.11.11.11",
"myservice1Id": "ee0f77c9-ef15",
"type": "type1",
"oRes": {
"status": "PASS"
},
"mylist": {
"listType": "list1",
"createdAt": "2020-12-07"
}
},
{
"hostname": "cde.com",
"ipAddress": "12.12.12.12",
"type": "type2",
"myservice1Id": null,
"vRes": {
"status": "FAIL"
}
}
]
}
Here, one thing to notice is that all the 3 if blocks can be executed in parallel because they are independent of each other.
Can I use Promise.all to execute all the 3 if blocks in parallel?
If yes, how the updated code will look like using Promise.all?
Simplest tweak would be to push each Promise to an array inside the ifs:
const proms = [];
if (hostName !== null && firstData.rows[i].myservice1Id !== null) {
proms.push(
myService2(hostName)
.then(aRes => firstData.rows[i].mylist = aRes[0].dataValues)
);
}
// other ifs changed around the same way
await Promise.all(proms);
You could also make the code easier by making the hostName check only once, and it looks like you're iterating over the whole array, which can be done more easily by invoking the iterator:
try {
const firstData = await myservice1.myservice1Func();
for (const row of firstData.rows) {
const hostName = row.hostname;
if (hostName === null) continue;
const proms = [];
if (row.myservice1Id !== null) {
proms.push(
myService2(hostName)
.then(aRes => row.mylist = aRes[0].dataValues)
);
}
// etc
Hi you have bit of code alterations,
for(let i=0; i<firstData.total; i++){
const hostName = firstData.rows[i]['hostname'];
//check if condition inside the service and return a null (a promise)
Promise.all([myService2(hostName), myService3(hostName), myService4(hostName)]).then((values) => {
console.log(values);
//[resutl1,null,result3]
});
}
Now the problem here is you have to wait until the slowest iteration to complete,
You can fix that with promise pool use,
#supercharge/promise-pool
MDN Promise Medium Blog Source

API Call Before Next Iteration Starts in Loop

I would like to send a POST request to a certain app through their API. What I am trying to do is to process the input data (called data) and send a POST request on one record by one record in the loop. Then, I delete the corresponding object in data for optimization purpose. I know that because of the asynchronous feature of JavaScript, the loop finishes before the function gets called. However, even though I wrap the api function in IIFE or wrap it in an async function with await(the code is below), the compiler still gives me function calls with the same parameter which is the last object. So, when I see created records on the app, David's information was generated three times. The screenshot below is each record object after being processed. If you could tell me ways of triggering the api call before the next iteration in the loop, that would be greatly appreciated.
const obj = [];
var record = {};
var data = [
{
"userId": "123",
"name": "John",
"phoneNumber": "123-456-6789"
},
{
"userId": "345",
"name": "Summer",
"phoneNumber": "535-631-9742"
},
{
"userId" : "789",
"name": "David",
"phoneNumber": "633-753-1352"
}
]
var dataLen = data.length;
var people = data;
createKeyValue = ((key, value) => {
var temp = {};
temp["value"] = value;
obj[key] = temp;
});
apiCall = ((record) => {
clientInformation.record.addRecord.then((resp) => {
console.log(resp);
}).catch((err) => {
console.log(err);
});
});
async function asyncFunction(record) {
let promise = new Promise((resolve, reject) => {
setTimeout(() => apiCall(record), 1000)
});
let result = await promise;
console.log(result);
}
while (dataLen > 0) {
for (let [key, value] of Object.entries(data[0])) {
switch(key) {
case 'userId':
createKeyValue(key, value);
break;
case 'name':
createKeyValue(key, value);
break;
default:
}
}
record["record"] = obj;
asyncFunction(record);
data.shift();
dataLen -= 1;
}
Here is the screenshot of how each processed data looks like.
I think you haven't understand how the for loop inside the while works. The data should be incremented each time to get the next array inside data.
The data[0] => { userId: 123 ... }, data[1] => { userId: 345 ... } and so on .
At each for loop iteration checks the 3 elements of each sub array, so each time temp stores the key values for userId and name. So when the loop finishes, the temp contains as key => userId, name and the corresponding values.
var data = [
{
"userId": "123",
"name": "John",
"phoneNumber": "123-456-6789"
},
{
"userId": "345",
"name": "Summer",
"phoneNumber": "535-631-9742"
},
{
"userId" : "789",
"name": "David",
"phoneNumber": "633-753-1352"
}
]
var dataLen = data.length;
let i = 0 ;
while ( i < dataLen) {
let temp = [];
for (let [key, value] of Object.entries(data[i])) {
if(key == 'userId' || key == 'name'){
temp[key] = value;
}
}
//Just to print the values and understand
for(let k in temp){
console.log(k+" -> "+temp[k]);
}
//here you will pass the temp values to functions
console.log(" At each iteration execute the required functions ");
//asyncFunction(temp);
i += 1;
}

get element index of an object

i need to get the index of an element in this object (returned as JSON.parse(data)), i tried with findIndex
datosReserva, datosReserva.Reservas and nothing... it says findIndex is not a function.
function checkReserva(){
var options = {
'method': 'GET',
'uri': urlAPI,
'headers': {
'Content-Type': 'application/x-www-form-urlencoded',
}
};
request(options, function (error, response) {
let reserva;
if (error){
throw new Error(error);
}else {
// console.log(response.body);
reserva = response.body;
//console.log(reserva)
}
return checkIndex(reserva, "2929 25-06-2020 10:00");
//"2929 25-06-2020 10:00" for testing
});
}
function checkIndex(datosReserva, reserva) {
const elemento = (element) => element.reserva == reserva;
console.log(datosReserva.findIndex(elemento))
}
{
"Reservas": [
{
"reserva": "2929 22-06-2020 11:20",
"id": "1",
"status": "on"
},
{
"reserva": "2929 25-06-2020 10:00",
"id": "5",
"status": "on"
}
]
}
var Reservas = Json.parse(response.body).Reservas;
return checkIndex(Reservas , "2929 25-06-2020 10:00");
function checkIndex(Reservas, reserva) {
let index = -1;
Reservas.forEach((element, idx)=>{
if(element.reserva == reserva) {
index = idx;
}
});
return index;
}
well i found the solution. I needed to parse the response to object. Thank you everyone!!
function checkIndex(datosReserva, stringReserva){
var reservas = JSON.parse(datosReserva)
const elemento= (element) => element.reserva == stringReserva;
var index = reservas.Reservas.findIndex(elemento);
console.log(reservas.Reservas.findIndex(elemento));
//return index;
}

Return 1 array of several api call

Is it possible to create a function who return an array of result of several api call ?
Instead of this :
var func1;
var func2;
var func3;
apicall1().then((res) => {
func1 = res;
});
apicall1("string").then((res) => {
func2 = res;
});
apicall1(int).then((res) => {
func3 = res;
});
Have something like this :
var result = [];
var Json = "{
"functions": [{
"name": "apicall1",
"args": null
}, {
"name": "apicall2",
"args": "string"
}, {
"name": "apicall2",
"args": [0, "string"]
}]
}";
MyFunction(Json) {
for (i = 0; i < functions.lenght; i += 1) {
functions[i].name(functions[i].args).then((res) => { result.push(res); });
}
return result;
}
I juste search something to avoid to have X callapi one behind the other.
Thanks ;D
You can use Promise.all to get results in an array:
Promise.all([apicall1(), apicall1("string"), apicall1(int)])
.then(results => {
// Destructure the results into separate variables
let [func1, func2, func3] = results;
//access the results here
});
You should use
Promise.all([ api1,api2,api2,...]).then(function(results){
}).catch(function(err){
})
result will be an array with all responses in respective indexes. Here one thing you need to handle is exception. if any of the API call occurs in any kind of exception it will go to catch.
If you want to trigger the calls one after the other, you can use async/await :
https://hackernoon.com/6-reasons-why-javascripts-async-await-blows-promises-away-tutorial-c7ec10518dd9
let result = [];
let funcs = [{
"name": "apicall1",
"args": null
}, {
"name": "apicall2",
"args": "string"
}, {
"name": "apicall2",
"args": [0, "string"]
}]
async makeCalls() {
for (let func of funcs) {
let res = await func.name(func.args)
result.push(res)
}
return result;
}
makeCalls()

PouchDB emit object from an array of objects

I would like to search trough an array of objects (that are encapsulated in one big object), and emit only the one of the internal objects. So let's suppose I have a JSON inserted into PouchDB that is looks like this:
{
"_id": "5eaa6d20-2019-44e9-8aba-88cfaf8e02542",
"data": [
{
"id": 1452,
"language": "java"
},
{
"id": 18787453,
"language": "javascript"
},
{
"id": 145389721,
"language": "perl"
}
]
}
How to get PouchDB to return the following result when searching for a language with an id = 145389721:
{
"id": 145389721,
"language": "perl"
}
Thanks!
In the scenario above the easiest way, using typescript, is to write a temp query:
db.query((doc, emit) => {
for (let element of doc.data) {
if (element.id === 145389721) {
emit(element);
}
}
}).then((result) => {
for (let row of result.rows) {
console.log(row.key);
}
})
Using permanent queries it would have looked like this:
let index = {
_id: '_design/my_index',
views: {
"by_id": {
"map": "function(doc) {for (let element of doc.data) {emit(element.id, element); }}"
}
}
};
// save it
this.db.put(index).catch(error => {
console.log('Error while inserting index', error);
});
//query it
this.db.query('my_index/by_id', { startkey: 145389721, endkey: 145389721}).then(result => {
for (let row of result.rows) {
console.log(row.value);
}
}).catch(error => {
console.log('Error while querying the database with an index', error);
});

Categories

Resources