issue with promise Node.js - javascript

I have been trying to figure this out for quite some time and it's too confusing so i thought i'd ask.
var listenKey = "";
const createListenKey = async () => {
await axios({
url: "/api/v3/userDataStream",
method: "POST",
baseURL: "https://api.binance.com",
headers: {
"X-MBX-APIKEY":
"H48w9CLuTtTi955qWjcjjEKhh0Ogb3jnnluYucXXXXXXXXXXXXXXXX",
},
}).then((response) => {
var key = response.data.listenKey;
console.log(key, "created");
return key;
});
};
listenKey = createListenKey();
listenKey.then((key) => {
console.log(key);
});
the console.log in the last but one line is printing undefined. Why is that?
Thanks in advance!

You did not return anything from the async function createListenKey
const asynF = async ()=>{
Promise.resolve(1).then(res=>{
//Simulating response from axios call
console.log(res)
})
// you are not returning anyting from this function equivalent of => return ;
}
asynF().then(res=>{
//this would log undefined
console.log(res)
})
As you know async function returns a promise you have two options make the outer wrapper a async function as well and just use await like below
const key = await createListenKey(config)
or else
you could simply do this
return createListenKey(config).then(res=>{
listenKey = res
})
can't say much more without knowing context.
Might I suggest not to mix then and async wait together

Because the createListenKey() function doesn't return anything. The return statement in the then clause inside that function is scoped in the then block. To return a value from an async function, you need to do something like this.
const createListenKey = async () => {
const response = await axios({
url: "/api/v3/userDataStream",
method: "POST",
baseURL: "https://api.binance.com",
headers: {
"X-MBX-APIKEY":
"H48w9CLuTtTi955qWjcjjEKhh0Ogb3jnnluYucXXXXXXXXXXXXXXXX",
},
})
var key = response.data.listenKey;
console.log(key, "created");
return key;
};

Related

fetch request returning promise [duplicate]

This question already has answers here:
How to return many Promises and wait for them all before doing other stuff
(6 answers)
Closed 4 months ago.
i created a function named getCartItems which calls getSingleItems passing id as argument. if i log the json result in getSingleItem it is showing object of the product correctly but when i try to access the function call value i get a promise how to resolve it?
const getSingleItem = async (id)=>{
const response = await fetch("http://localhost:4000/products/"+id, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
})
const json = await response.json();
return json;
}
const getCartItems = () => {
let currArr = JSON.parse(localStorage.getItem('cart'));
let newArr = currArr.map( async (el)=>await getSingleItem(el.id))
console.log(newArr);
setCartItems(newArr);
}
useEffect(()=>{
getCartItems();
}, [])
if try to use for loop instead of map it shows promise pending and throws connection error.
You need to resolve the promises from the map method with Promise.all and await for it before setting the cartItems state.
const getSingleItem = async (id)=>{
const response = await fetch("http://localhost:4000/products/"+id, {
method: 'GET',
headers: {
'Content-Type': 'application/json'
},
})
const json = await response.json();
return json;
}
const getCartItems = async () => {
let currArr = JSON.parse(localStorage.getItem('cart'));
let newArr = await Promise.all(currArr.map( async (el)=>await getSingleItem(el.id)))
console.log(newArr);
setCartItems(newArr);
}
useEffect(()=>{
getCartItems();
}, [])

How to know when the map function ends?

I have a "answersRequest" function, gets the id of the answers it writes to the "b" list
const answersRequest = () => {
let b = [];
answers.map(answer => {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
}).then(resp => {
b.push(resp.data.id)
})
})
}
And on completion of the map function, the below function needs to be run
const a = () => {setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: b}]); setAnswers([])};
but I don't know how to find out when the map function ends
help me please
You basically need to push the return values from the axios call to an array and then use Promise.allSettled() or Promise.all() to wait for all the responses before you can continue processing that data.
// Just faking an axios call for this example:
function mockedAxios({ data }) {
return new Promise((resolve) => {
setTimeout(() => {
resolve({
data: {
id: Math.random().toString(36).substr(2, 9),
result: data * 2,
},
});
}, 1000 + Math.random() * 2000)
});
}
async function answersRequest(answers) {
const promises = answers.map((answer) => {
// Return each promise here:
return mockedAxios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
});
// No need for a then block here, you can do it below in the `allSettled`'s `then`:
// .then((resp) => {
// return resp.data.id;
// });
});
// Wait for all responses and process the data:
const IDs = await Promise.allSettled(promises).then((result) => {
// result looks like { status: "fulfilled", value: { data: { id, result } } }
return result.map(r => r.value.data.id);
});
return IDs;
}
async function update() {
// You can now call and await this function from any other async function:
const IDs = await answersRequest([1,2,3,4,5]);
console.log(IDs);
// And then, one you get the result, do whatever you need to do with it:
// const a = () => {
// setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: IDs }]);
// setAnswers([]);
// };
}
update();
You can use Promise.all to resolve all promises at once.
const answersRequest = () => Promise.all(
answers.map(answer =>
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
})
)
);
Promise.all takes all the Promises passed to it (in this case, they are the HTTP requests) and only resolves when all the Promises are resolved. So, it's sending all the HTTP requests and waiting for all of them to finish. After that, the value of the returned Promise is an array containing all the responses, which means you don't need a separate variable for b anymore.
Then you can use Promise.then to call the second function.
answersRequest().then(values => {
setQuestionsBlok(
[...questionsBlok,
{
...questionBlokInputs,
answers: values.map(response => response.data.id)
}
]
);
setAnswers([]);
});
Here, values is an array containing all the responses from the requests. Then, the map call extracts all the id's from the response.
At first you should enable asynchronous to your requests.
After that you can call the function at the end of the loop like this:
const answersRequest = () => {
let i = 0; // Loop counter
let b = [];
// It's called at the end of requests
const funcA = (b) => {
setQuestionsBlok([
...questionsBlok,
{...questionBlokInputs, answers: b}
])
setAnswers([])
}
// Post answers request function
const createAnswers = async (answer) => {
return await axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
})
}
answers.map(answer => {
i++; // Increase loop counter value
createAnswers(answer).then(resp => {
b.push(resp.data.id)
// Runs specified function at the end of requests
if(i === answers.length) {
funcA(b)
}
})
})
}
You can use async/await to prompt your function to pause execution until a step completes:
const answersRequest = async () => {
let b = [];
await answers.map(answer => {
axios({
method: 'POST',
url: 'http://127.0.0.1:8000/api/answers/',
data: answer
}).then(resp => {
b.push(resp.data.id)
})
})
// execution pauses here
setQuestionsBlok([...questionsBlok, {...questionBlokInputs, answers: b}]); setAnswers([])
}
In this manner, b will be defined as desired for the setQuestionsBlok call.

Confused by async behavior

I'm using a try/catch to make some fetch requests, then I am extracting the title from the HTML and adding it to my object 'sleekResponse'
When I try to parse the body and add it to that object I'm having issues with the return value not including the title that I extracted from the HTML
I know this has something to do with asynchronicity, or my shallow understanding of Promises, but I can't tell why the return value is different from the value it's logging just before it's sent.
async function fetchUrl(url) {
console.log(url);
try {
const myInit = {
mode: 'cors'
}
let sleekResponse = {};
await fetch(url, myInit).then(function (response) {
sleekResponse.redirected = response.redirected;
sleekResponse.status = response.status;
return response;
})
.then((response) => titleWait(response))
.then((res) => sleekResponse.title = res)
function titleWait(response) {
Promise.resolve(response.text()).then((res) => {
a = res.split('<title>');
b = a[1].split('</title>')
sleekResponse.title = b[0];
return sleekResponse;
})
console.log(sleekResponse);
return sleekResponse;
}
console.log(sleekResponse); // This logs the correct value
return sleekResponse; // when it's returned it doesn't show the title that was added
} catch (err) {
return `${err}`;
}
}
I've tried so many things I don't remember everything that I tried. I know that I'm missing something that might be obvious, but I still don't understand why the console.log value is different from the value returned one line later.
The main issue is that titleWait doesn't return its own promise:
function titleWait(response) {
return Promise.resolve(response.text()).then((res) => {
a = res.split('<title>');
b = a[1].split('</title>')
sleekResponse.title = b[0];
return sleekResponse;
});
}
It's still a very convoluted way to write it. This is better:
async function titleWait(response) {
const res = await response.text());
const a = res.split('<title>');
const b = a[1].split('</title>')
sleekResponse.title = b[0];
return sleekResponse;
}
i hope i can a litel help
this basic fetch();
const response = await fetch('your url')
const data = await response.json();
console.log(data);

Promise { <pending> } - for last async function

I have two main functions. The first one gets the SOAP data from an API. The second one parses it to json and then formats it into the object I need to store. I have been logging and seeing the return values, and as of so far until now, it's been fine. However, I am calling exports.createReturnLabelfrom my test file and all I can see is Promise { <pending> } . I am returning a value at the last function. Does this code look weird to your? How can I clean it up?
const soapRequest = require('easy-soap-request');
const xmlParser = require('xml2json')
exports.createReturnLabel = async () => {
const xml = hidden
const url = 'https://ws.paketomat.at/service-1.0.4.php';
const sampleHeaders = {
'Content-Type': 'text/xml;charset=UTF-8',
};
const auth = async () => {
const {
response
} = await soapRequest({
url: url,
headers: sampleHeaders,
xml: xml,
timeout: 2000
});
const {
body,
statusCode
} = response;
return body
}
const fetchLabel = async () => {
const soapData = await auth();
try {
const json = xmlParser.toJson(soapData)
const labelData = JSON.parse(json)["SOAP-ENV:Envelope"]["SOAP-ENV:Body"]["ns1:getLabelResponse"]
return {
courier: 'dpd',
tracking_number: labelData["return"]["paknr"],
barCode: labelData["return"]["barcodecontent"],
printLabel: labelData["return"]["label"],
_ref: null
}
} catch (e) {
return (e)
}
}
return fetchLabel()
}
calling from my test file return console.log(file.createReturnLabel())
There's an async function call inside your code.
Should be: return await fetchLabel(), so that it awaits for completion before going on its merry way.

How do I chain get requests and concatinate the result of both into an array JS/Node

Current code is sloppy, I know. I am still iffy on then method.
What each get call returns
an array with some, not all, results
What I need
to pass two different uri and concatenate the result of both and then export it as module
e.g. getinfo(uri).getinfo(uri2).then(concatenated results)
CODE
const request = require('request-promise');
const getInfo = (uri) => {
// Return new promise
return request({
method: 'GET',
uri: uri,
json : true,
headers: {
'User-Agent': 'Request-Promise'
}
});
}
const promise = getInfo(url1).then((val) => {
let store = [];
getInfo(url2).then((val2) => {
store = store.concat(val2.array);
return store;
})
});
//ideally
export promise;
You just need to use .then correctly, and not discard the result of the first request
const request = require('request-promise');
const getInfo = (uri) => {
// Return new promise
return request({
method: 'GET',
uri: uri,
json : true,
headers: {
'User-Agent': 'Request-Promise'
}
});
}
// using promise.then
const result = (url1, url2) => getInfo(url1)
.then(val1 => getInfo(url2)
.then(val2 => val1.array.concat(val2.array))
);
// or async/await
const result = async (url1, url2) => {
const val1 = await getInfo(url1);
const val2 = await getInfo(url2);
return val1.array.concat(val2.array);
};
// both requests done at the same time
const result = (url1, url2) => Promise.all([
getInfo(url1),
getInfo(url2)
]).then(([val1, val2]) => val1.array.concat(val2.array));
export result;
// usage
const fn = require("./module.js"); // whatever you call the above file
fn("url1", "url2").then(result => {
// use result here
});
To explain each incarnation of result - it may be easier to write it out using regular functions so I can add comments
const result = function(url1, url2) {
return getInfo(url1)
.then(function(val1) {
return getInfo(url2)
.then(function(val2) {
return val1.array.concat(val2.array));
})
})
}
Usually you try to avoid "nesting" .then's like this, but since the end result requires both val1 and val2, it's unavoidable (not really, but, lets say it is)
This is where async/await shines
const result = async (url1, url2) => {
const val1 = await getInfo(url1);
const val2 = await getInfo(url2);
return val1.array.concat(val2.array);
};
There's no need to even rewrite that, because it's clear!
However, you want to run in Parallel
const result = (url1, url2) => Promise.all([
getInfo(url1),
getInfo(url2)
]).then(([val1, val2]) => val1.array.concat(val2.array));
Promise.all takes an array of promises, and returns a promise that resolves to the array of resolved results
([val1, val2]) => //rest of code
in case you didn't know is like
(results => {
let val1 = results[0];
let val2 = results[1];
// rest of code
So, that should be fairly easy to understand as it is

Categories