I'm building a website in Javascript, and I have this problem:
I want to do something like that.
First function calls server X.
The second function also calls server X, but only after the first is completely finished.
func2afterFunc1 = async () => {
await func1Open();
await func2Use();
}
export const func1Open = () => (dispatch) => {
axios
.post('/callToFunc1', "")
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
};
//basically call to this function to signup
exports.callToFunc1 = (req, res) => {
serverX
.open()
.then((data) => {
console.log(data)
return res.status(201).json("wasOpen");
})
.catch((err) => {
console.error(err);
return res.status(500).json("error");
});
};
export const func2Use = (user) => {
return async (dispatch) => {
serverX
.useAfterOpened()
.then((data) => {
console.log(data);
})
.catch((err) => {
console.error(err);
});
}
}
Related
I have a little problem, I need the makeZip function to wait for the takeScreenshot function to take all the screenshots it needs, how do I do this while taking care of best practices?
(I know at this point "then" doesn't make sense with the post method, I just tried it my way before but it didn't work the way I wanted)
Function:
const takeScreenshot = (url) => {
const resolutionsArray = Object.values(resolutions);
resolutionsArray.map(async (mediaSize) => {
webshot(url, setFileName(url, mediaSize), setOptions(mediaSize), (err) => {
if (!err) {
console.log("screenshot taken!");
}
});
});
};
calling functions:
app.post("/", async (req, res) => {
const { url } = req.body;
takeScreenshot(url)
.then((url) => makeZip(url))
.then((url) => sendEmail(url))
.then((message) => res.send(message))
.catch((err) => console.log(err));
});
My suggestion is:
to use Promise.all or Promise.allSettled when you need to handle several promises
extract callback of map fn
const makeWebshot = (argsHere) => new Promise((reselove, reject) => {
webshot(url, setFileName(url, mediaSize), setOptions(mediaSize), (err) => {
if (err) return reject(err);
return resolve();
});
});
Update takeScreenshot to
const takeScreenshot = (url) => {
const resolutionsArray = Object.values(resolutions);
return Promise.all(resolutionsArray.map((mediaSize) => makeWebshot(argsHere)));
};
When dealing with a list of Promises you will want to use Promise.all to wait for them all to resolve. Here is a simple example:
const list = [1,2,3];
const all = list.map(i => new Promise((resolve, reject) => {
setTimeout(() => {
console.log(i);
resolve(i*2);
}, 100);
}));
Promise.all(all).then(console.log)
In your case it would be something like this:
const takeScreenshot = (url) =>
Object.values(resolutions).map(async (mediaSize) => {
webshot(url, setFileName(url, mediaSize), setOptions(mediaSize), (err) => {
if (!err) {
console.log("screenshot taken!");
}
});
});
app.post("/", async (req, res) => {
const { url } = req.body;
Promise.all(takeScreenshot(url))
.then((listOfUrls) => ...
});
But since I don't know what webshot returns, I can't tell you what the processing of the listOfUrls should look like.
I will be calling three different endpoints in a project I am working on. The functions handling the requests are all the same apart from the different urls I will be calling. Below is an example of my code
const handleSubmitPhoneNumber = (e, next) => {
e.preventDefault();
const payload = {
"phone": user.phone
}
const postPhoneNumber = async () => {
setLoading(true)
await axios.post("https://jsonplaceholder.typicode.com/users", payload)
.then(response => {
setLoading(false)
console.log(response)
let res = response;
if (res.data.id === 11) {
next();
}
})
.catch(error => {
console.log(error)
});
}
postPhoneNumber();
}
const handleSubmitVerificationCode = (e, next) => {
e.preventDefault();
const payload = {
"verificationCode": user.verificationCode
}
const postVerificationCode = async () => {
setLoading(true)
await axios.post("https://jsonplaceholder.typicode.com/users", payload)
.then(response => {
setLoading(false)
console.log(response)
let res = response;
if (res.data.id === 11) {
next();
}
})
.catch(error => {
console.log(error)
})
}
postVerificationCode();
}
how can I write this code to avoid repetition since everything is the same apart from the base urls.
Please try this.
const handleSubmitPhoneNumber = (e, next) => {
e.preventDefault();
const payload = {
"phone": user.phone
}
postMethod("https://jsonplaceholder.typicode.com/users", payload, next);
}
const handleSubmitVerificationCode = (e, next) => {
e.preventDefault();
const payload = {
"verificationCode": user.verificationCode
}
postMethod("https://jsonplaceholder.typicode.com/users", payload, next);
}
const postMethod = async (url, payload, next) => {
setLoading(true)
await axios.post(url, payload)
.then(response => {
setLoading(false)
console.log(response)
let res = response;
if (res.data.id === 11) {
next();
}
})
.catch(error => {
console.log(error)
})
}
Make a function just for your post requrest:
async function POST(url, payload, next) {
setLoading(true)
await axios.post(url, payload)
.then(response => {
setLoading(false)
console.log(response)
let res = response;
if (res.data.id === 11) {
next();
}
})
.catch(error => {
console.log(error)
})
}
Then you can just use this function in your code like this:
const handleSubmitPhoneNumber = (e, next) => {
e.preventDefault();
const payload = {
"phone": user.phone
}
POST("https://jsonplaceholder.typicode.com/users", payload, next)
const handleSubmitVerificationCode = (e, next) => {
e.preventDefault();
const payload = {
"verificationCode": user.verificationCode
}
POST("https://jsonplaceholder.typicode.com/users", payload, next)
}
A slightly cleaner version of the idea expressed in the other answers might look like this:
const postMethod = (url, getPayload) => async (e, next) => {
e.preventDefault();
setLoading(true)
await axios.post(url, getPayload())
.then(response => {
setLoading(false)
console.log(response)
let res = response;
if (res.data.id === 11) {
next();
}
})
.catch(error => {
console.log(error)
})
}
const handleSubmitPhoneNumber = postMethod (
"https://jsonplaceholder.typicode.com/users",
() => {phone: user.phone}
)
const handleSubmitVerificationCode = postMethod (
"https://jsonplaceholder.typicode.com/users",
() => {verificationCode: user.verificationCode}
)
The main reason I like this better is that the handling of e and next doesn't vary between these handlers, so ideally it belongs in the common code.
I'm not happy though, in this or in the original, with the global access to user. Could this also be passed as a parameter?
In my function below, addToFlatList is only called once, even though I know there are several items in my database to be added. Seems like the fist addToFlatList is never resolved? What am I doing wrong?
photosSnapshot.forEach(async function(childSnapshot) {
await addToFlatList(childSnapshot.key, childSnapshot.val())(dispatch);
});
addToFlatList function:
const addToFlatList = (photoId, photoObj) => async(dispatch) => {
database.ref('users').child(photoObj.author).once('value').then((userSnapshot) => {
var userInfo = userSnapshot.val();
dispatch({type: "GOT_USER", payload: userInfo});
}).catch(error => {
dispatch({type: "GOT_ERROR"});
});
}
Update:
Tried to return dispatch like this. addToFlatList is still only called once.
const addToFlatList = async(photoId, photoObj) => {
return (dispatch) => {
database.ref('users').child(photoObj.author).once('value').then((userSnapshot) => {
var userInfo = userSnapshot.val();
dispatch({type: "GOT_USER", payload: userInfo});
}).catch(error => {
dispatch({type: "GOT_ERROR"});
});
}
}
Also tried this:
const addToFlatList = async(photoId, photoObj) => {
database.ref('users').child(photoObj.author).once('value').then((userSnapshot) => {
return (dispatch) => {
// never hit this point
var userInfo = userSnapshot.val();
dispatch({type: "GOT_USER", payload: userInfo});
}
}).catch(error => {
dispatch({type: "GOT_ERROR"});
});
}
You must return the promise:
const addToFlatList = (photoId, photoObj) => (dispatch) => {
return database.ref('users').child(photoObj.author).once('value').then((userSnapshot) => {
// ^^^^^^
var userInfo = userSnapshot.val();
return dispatch({type: "GOT_USER", payload: userInfo});
}).catch(error => {
return dispatch({type: "GOT_ERROR"});
});
};
Alternatively, you must await the promise so that your async function doesn't end prematurely:
const addToFlatList = (photoId, photoObj) => async (dispatch) => {
try {
const userSnapshot = await database.ref('users').child(photoObj.author).once('value');
// ^^^^^
var userInfo = userSnapshot.val();
return dispatch({type: "GOT_USER", payload: userInfo});
} catch(error) {
return dispatch({type: "GOT_ERROR"});
}
}
i have a problem:
I want that my axios make the requistion and after it makes the this.setState with the result saved in a variable.
My code:
componentDidMount() {
let mails = [];
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, () => {
this.state.employees.map(i => {
async axios.get(`/api/status/${i.mail}`)
.then(res => {
mails.push(res.data)
await this.setState({
mails: mails
})
})
.catch(err => console.log(err))
})
}))
.catch(err => console.log(err))
}
But it gives error syntax.
Best explanation: I want saved all results of the map in the variable mails and later to use the setState to changes the result of just a time.
Someone could tell me where i'm wandering? Please.
You are using async await at the wrong places. async keyword must be used for a function that contains asynchronous function
await keyword needs to be used for an expression that returns a Promise, and although setState is async, it doesn't return a Promise and hence await won't work with it
Your solution will look like
componentDidMount() {
let mails = [];
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, async () => {
const mails = await Promise.all(this.state.employees.map(async (i) => { // map function contains async code
try {
const res = await axios.get(`/api/status/${i.mail}`)
return res.data;
} catch(err) {
console.log(err)
}
})
this.setState({ mails })
}))
.catch(err => console.log(err))
}
It's not a good practice to mix async/await with .then/.catch. Instead use one or the other. Here's an example of how you could do it using ONLY async/await and ONLY one this.setState() (reference to Promise.each function):
componentDidMount = async () => {
try {
const { data: employees } = await axios.get('/api/employee/fulano'); // get employees data from API and set res.data to "employees" (es6 destructing + alias)
const mails = []; // initialize variable mails as an empty array
await Promise.each(employees, async ({ mail }) => { // Promise.each is an asynchronous Promise loop function offered by a third party package called "bluebird"
try {
const { data } = await axios.get(`/api/status/${mail}`) // fetch mail status data
mails.push(data); // push found data into mails array, then loop back until all mail has been iterated over
} catch (err) { console.error(err); }
})
// optional: add a check to see if mails are present and not empty, otherwise throw an error.
this.setState({ employees, mails }); // set employees and mails to state
} catch (err) { console.error(err); }
}
This should work:
componentDidMount() {
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, () => {
this.state.employees.map(i => {
axios.get(`/api/status/${i.mail}`)
.then( async (res) => { // Fix occurred here
let mails = [].concat(res.data)
await this.setState({
mails: mails
})
})
.catch(err => console.log(err))
})
}))
.catch(err => console.log(err))
}
You put async in the wrong place
async should be placed in a function definition, not a function call
componentDidMount() {
let mails = [];
axios.get('/api/employee/fulano')
.then(res => this.setState({
employees: res.data
}, () => {
this.state.employees.map(i => {
axios.get(`/api/status/${i.mail}`)
.then(async (res) => {
mails.push(res.data)
await this.setState({
mails: mails
})
})
.catch(err => console.log(err))
})
}))
.catch(err => console.log(err))
}
I can't figure out where the issue lies...Based on my research of what this error means, It seems like somewhere I am either sending a request twice or sending a response twice. I don't see anywhere this is happening...
file1.js
export const wrapper = (req, res, next) => {
async function getValue(user) {
await getExpiration(user).then(response => {
if (response.condition) {
return res.status(401).json()
}
})
}
getValue(user)
}
...
file2.js
export const getExpiration = async user => {
return new Promise(function(resolve, reject) {
getOrgInfo(user.org_id)
.then(res => {
return resolve(res)
}).catch(err => reject(err))
}).catch(err => console.log(err))
}
}
...
file3.js
// this is a function that talks to my database and returns a promise
export const getOrgInfo = (org_id) => {
return kx('orgs').select('Expiration').where({'id': org_id})
}
can you try this:
file1.js
export const wrapper = async (req, res, next) => {
const response = await getExpiration(user);
if (response.condition) {
res.status(401).json()
} else {
next()
}
}
Try to call it directly:
getOrgInfo(user.org_id).then(response => {
if (response.condition) {
return res.status(401).json();
}
})
.catch(err => next(err));