In my project I use promise (code below), how it is possible, that promise still pending, when I used keyword await. Can someone help me figure out, what I'm doing wrong?
const getTs = async () => {
const response = await axios.get('...')
.then(res => res.data)
.catch(() => 'ERROR');
return response;
};
console.log(getTs()); // Promise { <pending> }
The await does only stop the execution of the async function body, nothing else. The caller is not blocked, the code is still asynchronous, and you get back a promise. If you want to log the result, you have to wait for it.
const getTs = () => axios.get('...').then(res => res.data).catch(() => 'ERROR');
getTs().then(console.log);
// ^^^^^
or
async function getTs() {
try {
const res = await axios.get('...');
return res.data;
} catch (e) {
return 'ERROR';
}
}
async function main() {
const response = await getTs();
// ^^^^^
console.log(response)
}
main();
getTs will be resolved once the request is resolved. So you have to await the response like :
const getTs = async () => {
const response = await axios.get('...')
.then(res => res.data)
.catch(() => 'ERROR');
return response;
};
getTs().then(response => console.log(response));
Related
I'm fetching data from a website but the process sometimes fails so I make the function to retry it. But I'm using a 15 seconds timeout, so when the timeout is triggered it will stop retrying the function and it will return some error message from the website.
This works fine in my local machine but when I deploy my code to Vercel (running on AWS Lambda as far as I know), the setTimeout is being completely ignored, so the fetchData function keeps running until it gets the correct response or until the server default 60 seconds timeout triggers.
Here's the code:
router.get('/test', async (req, res) => {
try {
const browser = await playwright.launchChromium({
headless: false });
const context = await browser.newContext();
const page = await context.newPage();
let timeout = false;
let fetchDataTimeout = setTimeout(() => {
timeout = true;
}, 15000);
const fetchData = async () => {
await page.type('#code', '6824498040');
let data = await (
await Promise.all([
page.waitForResponse(
(response) =>
response.url() === `${env.API_URL2}` && response.status() === 200,
{ timeout: 10000 },
),
page.click('#btn-check'),
])
)[0].json();
if (data.errors && !timeout) {
await page.reload();
return await fetchData();
} else {
clearTimeout(fetchDataTimeout);
return data;
}
};
let data = await fetchData();
await browser.close();
res.json({
status: 200,
message: data,
});
} catch (error) {
console.error(error);
return res.status(500).send({ 'Server Error': `${error}` });
}
});
I read that you have to wrap the setTimeout into a Promise and return it as an async function. Like this:
const timeOut = async (t) => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve(`Completed in ${t}`)
}, t)
})
}
await timeOut(15000).then((result) => console.log(result))
But this will trigger the 15 seconds wait always. I need to discard the waiting if I get the correct response from fetchData and trigger the timeout if I don't 15 seconds after I start trying.
Any ideas???
The solution was quite simple. Since AWS Lambda requires an async function to properly wait the timeouts, I just had to wrap the timeout in a Promise. But then what did the trick was wrapping both functions, the timeout and the fetchData, in a Promise.race() method. By doing this, the promise that resolves first will stop the other one from running.
The code is now like this:
router.get('/test', async (req, res) => {
try {
const browser = await playwright.launchChromium({headless: false });
const context = await browser.newContext();
const page = await context.newPage();
const timeout = () =>
new Promise((resolve, reject) => {
setTimeout(() => {
reject('FUNCTION TIMEOUT');
}, 12000);
});
const fetchData = async () => {
await page.type('#code', '6824498040');
let response = await (
await Promise.all([
page.waitForResponse(
(res) =>
res.url() === `${env.API_URL2}` && res.status() === 200,
{ timeout: 10000 },
),
page.click('#btn-check'),
])
)[0].json();
if (data.error) {
await page.reload();
return await fetchData();
} else return data;
}
};
let data = await Promise.race([fetchData(), timeout()]);
await browser.close();
res.json({
status: 200,
message: data,
});
} catch (error) {
console.error(error);
return res.status(500).send({ 'Server Error': `${error}` });
}
});
I implemented a 12 seconds timeout instand of 15. I tested this on Vercel (AWS Lambda) and it works fine.
Thanks everybody, especially dandavis, this implementation was his idea.
Anyway, I hope it helps.
hi i got some problem here i want to return the result after getting target content on the getnada email, but its always return undefined, can somebody help me here.
const getEmailData = async (getExtention) => {
// return getExtention
await axios
.get(`https://getnada.com/api/v1/inboxes/${getExtention}`)
.then(async (res) => {
const getEmailCount = await res.data.msgs.length
if (parseInt(getEmailCount) >= 1) {
// console.log('Berhasil berhasil Hore')
const getDataEmail = await axios.get(
`https://getnada.com/api/v1/messages/html/${res.data.msgs[0].uid}`
)
if (getDataEmail) {
console.log('Data berhasil')
const getOTPEmail = await Promise.all(getDataEmail.data)
return getOTPEmail
} else {
console.log('Data Gagal')
}
}
})
.catch(() => {
getEmailData(getExtention)
})
}
here is the code of my procces on getting The content i want to get
but after i return the getOTPEmail its always undefined
the result i declare is like this
const getDataOTP = await getEmailData(getExtention)
console.log(getDataOTP)
can someone explain me whats wrong with this code ?
One easy way to do it would be to move the code from the .then callback "outside" as follow :
const getEmailData = async (getExtention) => {
// return getExtention
try {
let res = await axios
.get(`https://getnada.com/api/v1/inboxes/${getExtention}`);
const getEmailCount = await res.data.msgs.length
if (parseInt(getEmailCount) >= 1) {
// console.log('Berhasil berhasil Hore')
const getDataEmail = await axios.get(
`https://getnada.com/api/v1/messages/html/${res.data.msgs[0].uid}`
)
if (getDataEmail) {
console.log('Data berhasil')
const getOTPEmail = await Promise.all(getDataEmail.data)
return getOTPEmail
} else {
console.log('Data Gagal')
}
}
} catch (e) {
getEmailData(getExtension);
}
}
Also, you will notice that this part const getEmailCount = await res.data.msgs.length probably doesn't work as you would expect because length isn't a promise.
But why isn't it working as is ?
Using .then is using a callback on the promise return by axios.get so your getEmailData function doesn't return anything. It is calling axios.get which is asynchronous and provide a callback once the promise has been resolved, and leaving.
Is there a way to make this work using .then ?
There is, with the following steps :
initialize a Promise in getEmailData
remove the await in front of axios.get call.
call resolve from the initialized Promise in .then callback
Pseudo-Code :
const getEmailData = async (getExtension) => {
return new Promise((resolve) => {
axios.get().then((res) => {
resolve(res);
})
});
}
But it is way easier to write, easier to read and cleaner to use await, otherwise it's becoming a callback hell :)
I think the error is here
if (parseInt(getEmailCount) >= 1) {
// console.log('Berhasil berhasil Hore')
const getDataEmail = await axios.get(
`https://getnada.com/api/v1/messages/html/${res.data.msgs[0].uid}`
)
if (getDataEmail) {
console.log('Data berhasil')
const getOTPEmail = await Promise.all(getDataEmail.data)
return getOTPEmail
} else {
console.log('Data Gagal')
}
because you defined the 'getDataEmail' variable inside the if statement and you want to use it outside it .
so ,I think you have to do it like this
let getDataEmail ;
if (parseInt(getEmailCount) >= 1) {
// console.log('Berhasil berhasil Hore')
getDataEmail = await axios.get(
`https://getnada.com/api/v1/messages/html/${res.data.msgs[0].uid}`
)
if (getDataEmail) {
console.log('Data berhasil')
const getOTPEmail = await Promise.all(getDataEmail.data)
return getOTPEmail
} else {
console.log('Data Gagal')
}
I am getting login and password values in an asynchronous function and returning using destructuring. But when I try to use the data in another function, it outputs - undefined. Help please. In what the problem
async function authWithLoginAndPassword() {
const response = await fetch('');
const data = await response.json();
const logUser = data[0].login;
const passwordUser = data[0].password;
return { logUser, passwordUser }
}
submit.addEventListener('click', () => {
let register = authWithLoginAndPassword();
console.log(register.logUser, register.passwordUser)
})
All async functions return a promise that resolves to whatever value you return from that function. So, when you call authWithLoginAndPassword(), you have to use either .then() or await to get the resolved value from the promise that the function returns:
submit.addEventListener('click', async () => {
try {
let register = await authWithLoginAndPassword();
console.log(register.logUser, register.passwordUser)
} catch(e) {
// catch errors
console.log(e);
}
});
or
submit.addEventListener('click', () => {
authWithLoginAndPassword().then(register => {
console.log(register.logUser, register.passwordUser)
}).catch(err => {
console.log(err);
});
});
I have async function in async function. In the second I must wait when promises resolve or reject and after run other code below. But if promise reject my code stopping and no run other functions. How I can fix it?
await axios.all(promises).then(res => {
axios.patch("/url", { foo: bar }).then(async () => {
const promises2 = arr.map(item => {
return axios.post("/url-2", item)
});
await Promise.all(promises2)
.then(() => console.log("resolved")) //this not calling ever
.catch(() => console.log("failed")) //this not calling ever
console.log("This console log ever not working")
})
})
Promises aren't chained properly, axios.patch(...) promise isn't returned. await is syntactic sugar for then and catch, its purpose is to get rid of nested functions where possible. It should be:
const res = await axios.all(promises)
await axios.patch("/url", { foo: bar })
const promises2 = arr.map(item => {
return axios.post("/url-2", item)
});
try {
await Promise.all(promises2)
console.log("resolved"))
} catch (err) {
console.log("failed");
}
The order of your code is wrong. Of course if the first promise is rejected, then the rest will not be called.
Try rewriting your code this way:
let res = await axios.all(promises).catch(() => { console.log("failed"); return false; });
if (!res) {
// Do something when rejected
....
}
// Call the 2nd promise
let res2 = await axios.path("/url", {foo: bar}).catch(() => {console.log("failed 2"); return false; });
if (!res2) {
// Do something when the 2nd promise is rejected
...
}
// Call your last promise
let res3 = await Promise.all(promises2).catch(() => {console.log("failed 3"); return false; });
if (!res3) {
// Do something if it is rejected again
....
}
// Otherwise, do your thing
Try this code, it should pinpoint where the error or rejection is occurring (i.e. it's definitely before Promise.all(promises2) is run
await axios.all(promises)
.then(res => axios.patch("/url", { foo: bar }), err => {
throw `all(promises) failed with ${err}`;
})
.then(() => {
const promises2 = arr.map(item => {
return axios.post("/url-2", item);
});
return Promise.all(promises2)
.then(() => console.log("resolved")) //this not calling ever
.catch(err => {
throw `all(promises2) failed with ${err}`;
});
}, err => {
throw `patch failed with ${err}`;
})
.catch(err => console.error(err));
Note I've removed async/await, because in the code you've posted it is totally unnecessary
I got unexpected identifier but not sure what is the mistake. I'm using fetch which is already a promise.
async getUsers = () => {
const resp = await fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
return resp
}
getUsers().then(users => console.log(users))
Notice the position of the async keyword:
Not:
async getUsers = () => {
But:
getUsers = async () => {
Run:
getUsers = async () => {
const resp = await fetch('https://jsonplaceholder.typicode.com/posts/1')
.then(response => response.json())
return resp;
};
getUsers().then(users => console.log(users))
As per comments:
Should I chain then() in getUsers()? async/await suppose to eliminate then() am I right?
Yes, you can await any Promise. Or use both .then() sometimes and await at others (like does the code above). But you could just use async/await as well.
The example below uses no .then():
getUsers = async () => {
const resp = await fetch('https://jsonplaceholder.typicode.com/posts/1')
return resp.json();
};
(async () => {
// notice to use the await keyword, the code must be wrapped in an async function
const users = await getUsers();
console.log(users);
})();
Aside from the typo in the async word pointed by #acdcjunior, you're mixing async / await with the usual promise handling (.then()) which is not wrong but kind of defeats the point. Using only async / await would look like:
const getUsers = async () => {
const resp = await fetch('https://jsonplaceholder.typicode.com/posts/1');
return resp.json();
}
async function fetchUsers() {
try {
const users = await getUsers();
console.log(users);
} catch(err) {
console.log(err);
}
}
fetchUsers();
you have the syntax wrong:
const getusers = async () => {
...
}
const is optional
Your syntax of declaring your function is wrong, here's some explanation.
If getUsers is a method of a react component class the syntax should be :
getUsers = async () => {
const resp = await fetch(
'https://jsonplaceholder.typicode.com/posts/1'
).then(response => response.json());
return resp;
};
or :
async getUsers() {
const resp = await fetch(
'https://jsonplaceholder.typicode.com/posts/1'
).then(response => response.json());
return resp;
};
If it's outside of a react component class or in a stateless arrow function component you can use this syntax :
const getUsers = async () => {
const resp = await fetch(
'https://jsonplaceholder.typicode.com/posts/1'
).then(response => response.json());
return resp;
};
const getUsers = async () => {
try {
const resp = await fetch('https://jsonplaceholder.typicode.com/posts/1');
return resp.json();
} catch(e) {
console.error(e)
}
}
(async () => {
const users = await getUsers();
console.log(users)
})()
Use this, and run