problem awaiting the callback given to a function - javascript

I have a function who send a message to the server to get the answer and if the answer is true I want my application to send an error to the user. The problem is that I can't manage to await the callback in the Fetch function I wrote.
This is the function who send the question to the server.
async donglePaired(){
if (Platform.OS !=='ios'){
var pairedDevices = await BluetoothScanner.getPairedDevices();
console.log('Sending........');
let data={
data:pairedDevices,
};
new Api().fetch("bluetoothCheck",{devices:JSON.stringify(data),userid:this.state.probe.UID},(result) => {
if (!result.err) return false;
console.log("Dongle already paired");
return true;
//logNetworkState
});
}
}
This is the Api.fetch function i wrote
fetch(action,data,cb){
let url=Config.URL+"?version="+Config.VERSION+"&action="+action;
let post="";
let formData=new FormData();
for(let k in data) formData.append(k,data[k]);
for(let k in data) post+="&"+k+"="+encodeURIComponent(data[k]).replace(/%20/g,'+');
console.log(url+post);
console.log(url);
if (data.batch) console.log(data.batch);
let sending=true;
fetch(url,{
method: 'post',
body: formData
})
.then(function(response){
if (true) return response.json();
let txt=response.text();
console.log(txt);
return JSON.parse(txt);
})
.then(
(result)=>{
if (!sending) return;
sending=false;
console.log(JSON.stringify(result));
if (cb) cb(result);
},
(error)=>{
if (!sending) return;
sending=false;
console.log("fetch error");
console.log(error);
if (cb) cb();
}
);
setTimeout(()=>{
console.log("http timeout")
if (!sending) return console.log("nothing to abort");
if (cb) cb();
},Config.HTTP_TIMEOUT*1000)
}
}
And this is my main code where I wait for the first function donglePaired, and if donglePaired return true I send an error to the user.
let donglePaired = await this.props.app.donglePaired();
if (donglePaired) return this.props.app.setError("ERR_DONGLE");
The problem is that the program doesnt wait for donglePaired, despite of the await

your code here is inappropriate
let donglePaired = await this.props.app.donglePaired();
if (donglePaired) return this.props.app.setError("ERR_DONGLE");
Async function cannot return value normally unless it is a Promise
See my simple demo below!
async function test() {
const result = await asyncRequest()
return result
}
function asyncRequest() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('success')
}, 2000)
})
}
test().then((data) => {
console.log(data)
})

The snippets should give you an idea how to await the callback
Sending to the API
async function remove_configuration(filename) {
const data = { filename };
const options = {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(data)
};
await fetch('/delete', options);
}
Just Retrieving Data
async function display() {
let response = await fetch('/get-available-configurations')
let data = await response.json(); // JSON or Text what do you prefer
// do something with data
}

You could return an Promise.race() with your timeout function.
fetch(action, data, cb) {
let url = Config.URL + "?version=" + Config.VERSION + "&action=" + action;
let post = "";
let formData = new FormData();
for (let k in data) formData.append(k, data[k]);
for (let k in data)
post += "&" + k + "=" + encodeURIComponent(data[k]).replace(/%20/g, "+");
console.log(url + post);
console.log(url);
if (data.batch) console.log(data.batch);
let sending = true;
return Promise.race([
fetch(url, {
method: "post",
body: formData
})
.then(res => res.json())
.then(result => {
if (!sending) return;
sending = false;
return result;
}),
sleep(Config.HTTP_TIMEOUT * 1000)
]);
}
const sleep = ms => new Promise((_, rej) => setTimeout(rej("TIMEOUT"), ms));
It either returns you the value or it rejects with TIMEOUT or it rejects with an error from fetch
And donglePaired looks like this then. I have wrapped it with an try / catch
async donglePaired() {
if (Platform.OS !== "ios") {
var pairedDevices = await BluetoothScanner.getPairedDevices();
console.log("Sending........");
let data = {
data: pairedDevices
};
try {
let result = await new Api().fetch("bluetoothCheck", {
devices: JSON.stringify(data),
userid: this.state.probe.UID
});
if (!result.err) return false;
console.log("Dongle already paired");
return true;
//logNetworkState
} catch (err) {
console.log(err);
}
}
}

One possibility is to drop the async and change it to this:
donglePaired() {
return new Promise( function(resolve, reject) {
if (Platform.OS !=='ios'){
var pairedDevices = await BluetoothScanner.getPairedDevices();
console.log('Sending........');
let data={
data:pairedDevices,
};
new Api().fetch("bluetoothCheck",{devices:JSON.stringify(data),userid:this.state.probe.UID},(result) => {
if (!result.err) reject(false);
console.log("Dongle already paired");
resolve(true);
//logNetworkState
});
}
reject(false);
});
}
And:
this.props.app.donglePaired().then( (response) => {
// do something here, this will only run if the response is true
});

Related

Nodejs multiple axios get requests return a Primise

How to return a Promise from the multiple axios get requests?
I have below code.
async function main() {
const URL_1 = 'abc.com/get1/data1';
const result_1 = await getData(URL_1);
const URL_2 = 'abc.com/get2/data2';
const result_2 = await getData(URL_2);
}
async function getData(dataURI) {
let getURI = dataURI;
const config = {
headers: {
Authorization: `Bearer ${my-token-text}`,
},
};
var finalData = [];
// until we get the next URL keep sending the requests
while (getURI != null) {
try {
const getResult = await axios.get(getURI, config);
if (getResult.status === 200) {
const receivedData = getResult.data.value;
finalData.push(...receivedData);
// check if we have nextLink in the payload
if (Object.prototype.hasOwnProperty.call(getResult.data, 'nextLink')) {
getURI = getResult.data.nextLink;
} else {
getURI = null;
return finalData;
}
}
} catch (err) {
break;
}
}
return null;
}
What I am trying to achieve is:
async function main() {
const URL_1 = 'abc.com/get1/data1';
const result_1 = getData(URL_1);
promisesArray.push(result_1);
const URL_2 = 'abc.com/get2/data2';
const result_2 = getData(URL_2);
promisesArray.push(result_2);
await Promise.allSettled(promisesArray).then((results) => {
console.log('Promise All Done: ', results);
});
}
This why I can perform all the requests in parallel.
But when I update the function getData(dataURI) to return return new Promise then I get error for await axios.
async function getData(dataURI) {
return new Promise((resolve, reject) => {
// Same code as above
});
}
I get error:
SyntaxError: await is only valid in async function
As Promise is not async I cannot await in the Promise.
Have you tried:
return new Promise(async (resolve, reject) => {
// Same code as above
});

Making API Request with JavaScript

I have an assignment to complete a function that makes API requests using a name. This request will return a json object and this object has a 'height' field that the function should return. I tried but my solution odes not seem to work. Below is my code. Can someone point me in the right direction?
async function getHeight(name) {
let url = "sample url"
https.get(url, (resp) => {
let data = '';
resp.on('data', (chunk) => {
data += chunk;
});
resp.on('end', () => {
let result = (JSON.parse(data));
let result_data = result[data];
if(result_data == null){
return -1
} else{
let cataJson = (JSON.parse(result_data));
return cataJson["height"];
}
});
}).on("error", (err) => {
return -1;
});
}
async function getHeight(name) {
let url = "sample url"
try {
let res = await fetch(url);
return await res.json();
} catch (error) {
console.log(error);
}
}
this code should be some thing like what you need.
you make a get request to the url then you parse the given data to json format then the function returns that data.
You can use fetch with promise like this.
async function getHeight(name) {
return new Promise((resolve, reject)=>{
let url = "sample URL"
fetch(url)
.then(res=>res.json())
.then(data=>{
let result = (JSON.parse(data));
let result_data = result[data];
if(!result_data)resolve(-1)
else resolve((JSON.parse(result_data)).height)
})
.catch(e=>{reject()})
})
}
And to call the function
async function main(){
try{
var height = await getHeight("John");
console.log(height)
}catch(e){
console.log("Error Fetching height")
}
}
main()
const getHeight = async (name) {
let url = "url"
try {
let res = await fetch(url,{
method: "GET"
);
if (res.ok == true) {
return await res.json();
} else {
throw new Error("error")
}
} catch (error) {
console.log(error);
}
}

Retry fetch request doesn't return anything

This is the current code and what I've come up with:
function getToken() {
return new Promise(async (resolve, reject) => {
try {
let res = await fetch(url);
if (res.status === 418) {
setTimeout(getToken, 1000);
} else {
let token = await res.text();
console.log("1", token);
resolve(token);
}
} catch(e) {
reject(e);
}
});
}
async function test() {
let token = await getToken();
console.log("2", token);
}
test();
It logs 1 <token> but it doesn't log the other part like its supposed to (2 <token>). Is there something I'm missing or doing wrong?
My very naive approach would be a mix of a "sleep" function and standard async/await syntax (no need to mix then into it).
This does not take into consideration a possible infinite loop if the URL consistently returns a 418 http code.
The biggest thing to note is that I am returning getToken() in the retry and also returning token in the else. If we don't do this token inside test will always be undefined.
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
async function getToken() {
try {
let res = await fetch('https://httpstat.us/200');
if (res.status === 418) {
await sleep(1000);
return getToken();
} else {
let token = await res.text();
console.log("1", token);
return token;
}
} catch (e) {}
};
async function test() {
let token = await getToken();
console.log("2", token);
}
test();
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
function get(url, retryStatusCode) {
return new Promise(async (resolve, reject) => {
let found = false;
while (found !== true) {
try {
await sleep(1000);
await fetch(url).then(res => {
let text = res.text();
let status = res.status;
if (status !== retryStatusCode) {
found = true;
resolve(text);
}
});
} catch (error) {
reject(error);
}
}
});
};
Then await get(url, 404).
Use then
await fetch(url).then(res=>console.log(res).catch(err=>console.log(err);
I'm just logging the res here, you can do whatever you want with it

How to achieve recursive Promise calls in Node.js

I am calling an API where I can only fetch 1000 records per request,
I was able to achieve this using recursion.
I am now trying to achieve the same using promises, I am fairly new to Node.js and JavaScript too.
I tried adding the recursion code in an if else block but failed
var requestP = require('request-promise');
const option = {
url: 'rest/api/2/search',
json: true,
qs: {
//jql: "project in (FLAGPS)",
}
}
const callback = (body) => {
// some code
.
.
.//saving records to file
.
//some code
if (totlExtractedRecords < total) {
requestP(option, callback).auth('api-reader', token, true)
.then(callback)
.catch((err) => {
console.log('Error Observed ' + err)
})
}
}
requestP(option).auth('api-reader', token, true)
.then(callback)
.catch((err) => {
console.log('Error Observed ' + err)
})
I want to execute the method using promise and in a synchronous way,
i.e. I want to wait until the records are all exported to a file and continue with my code
I think its better to create your own promise and simply resolve it when your done with your recursion. Here's a simply example just for you to understand the approach
async function myRecursiveLogic(resolveMethod, ctr = 0) {
// This is where you do the logic
await new Promise((res) => setTimeout(res, 1000)); // wait - just for example
ctr++;
console.log('counter:', ctr);
if (ctr === 5) {
resolveMethod(); // Work done, resolve the promise
} else {
await myRecursiveLogic(resolveMethod, ctr); // recursion - continue work
}
}
// Run the method with a single promise
new Promise((res) => myRecursiveLogic(res)).then(r => console.log('done'));
Here's a clean and nice solution using the latest NodeJS features.
The recursive function will continue executing until a specific condition is met (in this example asynchronously getting some data).
const sleep = require('util').promisify(setTimeout)
const recursive = async () => {
await sleep(1000)
const data = await getDataViaPromise() // you can replace this with request-promise
if (!data) {
return recursive() // call the function again
}
return data // job done, return the data
}
The recursive function can be used as follows:
const main = async () => {
const data = await recursive()
// do something here with the data
}
Using your code, I'd refactored it as shown below. I hope it helps.
const requestP = require('request-promise');
const option = {
url: 'rest/api/2/search',
json: true,
qs: {
//jql: "project in (FLAGPS)",
}
};
/*
NOTE: Add async to the function so you can udse await inside the function
*/
const callback = async (body) => {
// some code
//saving records to file
//some code
try {
const result = await requestP(option, callback).auth('api-reader', token, true);
if (totlExtractedRecords < total) {
return callback(result);
}
return result;
} catch (error) {
console.log('Error Observed ' + err);
return error;
}
}
Created this code using feed back from Amir Popovich
const rp = require('Request-Promise')
const fs = require('fs')
const pageSize = 200
const options = {
url: 'https://jira.xyz.com/rest/api/2/search',
json: true,
qs: {
jql: "project in (PROJECT_XYZ)",
maxResults: pageSize,
startAt: 0,
fields: '*all'
},
auth: {
user: 'api-reader',
pass: '<token>',
sendImmediately: true
}
}
const updateCSV = (elment) => {
//fs.writeFileSync('issuedata.json', JSON.stringify(elment.body, undefined, 4))
}
async function getPageinatedData(resolve, reject, ctr = 0) {
var total = 0
await rp(options).then((body) => {
let a = body.issues
console.log(a)
a.forEach(element => {
console.log(element)
//updateCSV(element)
});
total = body.total
}).catch((error) => {
reject(error)
return
})
ctr = ctr + pageSize
options.qs.startAt = ctr
if (ctr >= total) {
resolve();
} else {
await getPageinatedData(resolve, reject, ctr);
}
}
new Promise((resolve, reject) => getPageinatedData(resolve, reject))
.then(() => console.log('DONE'))
.catch((error) => console.log('Error observed - ' + error.name + '\n' + 'Error Code - ' + error.statusCode));

Can't show response after post request

I'm having trouble when I try to show the answer of post request with node and request. I can see the response in the console in service, but it does not arrive into controller..why?
Thaaaanks!
Here is the code:
function postData(req, res, next){
eventService.getItems()
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
for(var i = 16 ; i < nameFilter.length; i++){
eventService.postData(nameFilter[i])
}
})
.then(response => {
console.log(response) // undefined
res.send(response)
})
.catch(error => {
console.log('error')
next(error)
})
}
module.exports = {postData}
service
postData(data) {
return new Promise(function (resolve, reject) {
request.post({
headers: {
'Content-Type': 'application/json',
'Authorization': 'Bearer ' + '00002'
},
url: 'url ',
json: data
},
function (error, response, body) {
if (error) {
reject(error)
} else {
console.log(response.body) // shows the message
resolve(response.body)
}
});
})
}
}
Let's focus on the following part of the code:
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
for(var i = 16 ; i < nameFilter.length; i++){
eventService.postData(nameFilter[i])
}
})
.then(response => { // the previous `then` didn't return anything so you shouldn't expect any argument to be passed here!
console.log(response) // undefined
res.send(response)
})
response is available in the context of the first then but not in the second! (this is the reason it's undefined).
In order to pass it to the second then you'll need to add return response after the for-loop of the first then:
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
for(var i = 16 ; i < nameFilter.length; i++){
eventService.postData(nameFilter[i])
}
return response; // <-- pass it here
})
.then(response => {
console.log(response) // and now you'll have it!
res.send(response)
})
You need to return something in every .then in the Promise if you want to use it in the next.
In this case there is not point creating a new .then and you code can be changed to:
function postData(req, res, next){
eventService.getItems()
.then(response => {
const result = response.body.items
const id = nameFilter.map(task => task.id = null)
const promises = []
// Should 16 be here? Seems like an error
for(var i = 16 ; i < nameFilter.length; i++){
promises.push(eventService.postData(nameFilter[i]))
}
// postData returns a promise, so above we build an array of all the promises
// then this line will wait for all of them to complete
return Promise.all(promises)
})
.then(allResults => {
// All results will now be the result of every call to `eventService.postData...`
console.log(allResults)
res.send(allResults)
})
.catch(error => {
console.log('error')
next(error)
})
}
module.exports = {postData}

Categories

Resources