可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I need to chain a few API requests from the Google Maps API, and I'm trying to do it with Axios.
Here is the first request, which is in componentWillMount()
axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p1)
.then(response => this.setState({ p1Location: response.data })) }
Here is the second request:
axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p2)
.then(response => this.setState({ p2Location: response.data }))
Then we have a third request, which is dependent on the first two being completed:
axios.get('https://maps.googleapis.com/maps/api/directions/json?origin=place_id:' + this.state.p1Location.results.place_id + '&destination=place_id:' + this.state.p2Location.results.place_id + '&key=' + 'API-KEY-HIDDEN')
.then(response => this.setState({ route: response.data }))
How can I chain these three calls so that the third happens after the first two?
回答1:
First off, not sure you want to do this in your componentWillMount
, because your component will not render until all this is done, its better to have it in componentDidMount
and have some default states that will update once done with these requests. Second, you want to limit the number of setStates you write because they might cause additional re-renders, here is a solution using async/await:
async componentDidMount() {
const firstRequest = await axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p1);
const secondRequest = await axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p2);
const thirdRequest = await axios.get('https://maps.googleapis.com/maps/api/directions/json?origin=place_id:' + firstRequest.data.results.place_id + '&destination=place_id:' + secondRequest.data.results.place_id + '&key=' + 'API-KEY-HIDDEN');
this.setState({
p1Location: firstRequest.data,
p2Location: SecondRequest.data,
route: thirdRequest.data,
});
}
回答2:
Have you used axios.all ? You can try with something similar:
axios.all([axios.get(`firstrequest`),
axios.get(`secondrequest`),
axios.get(`thirdrequest`)])
.then(axios.spread((firstResponse, secondResponse, thirdResponse) => {
console.log(firstResponse.data,secondResponse.data, thirdResponse.data);
}))
.catch(error => console.log(error));
This will take all your get and will put it inside a response that has to be called with .data like:
firstResponse.data
回答3:
I think you need something like this:
const firstRequest = axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p1)
.then(response => this.setState({ p1Location: response.data })) }
const secondRequest = axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p2)
.then(response => this.setState({ p2Location: response.data }))
const thirdRequest = axios.get('https://maps.googleapis.com/maps/api/directions/json?origin=place_id:' + this.state.p1Location.results.place_id + '&destination=place_id:' + this.state.p2Location.results.place_id + '&key=' + 'API-KEY-HIDDEN')
.then(response => this.setState({ route: response.data }))
Promise.all([firstRequest, secondRequest])
.then(() => {
return thirdRequest
})
回答4:
A little late to the party, but I like this pattern of chaining promises, returning them to keep the promise chain alive.
axios
.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p1')
.then(response => {
this.setState({ p1Location: response.data });
return axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p2');
})
.then(response => {
this.setState({ p2Location: response.data });
return axios.get('https://maps.googleapis.com/maps/api/geocode/json?&address=' + this.props.p3');
})
.then(response => {
this.setState({ p3Location: response.data });
}).catch(error => console.log(error.response));
回答5:
This is related to JS's Promises. You can solve it in different ways. The simplest way to me is that you should nest each request starting from first to third. That means starting from the first request, you should put your second axios.get(url)
into the first request's .then()
and put the third request into the second request's .then()
.
For promises in general you expect that inside the .then()
part promise is resolved and you can have access to the response
. So that by nesting, you can solve the problem of being asynchronous in a not so elegant way.
回答6:
For better performance and cleaner code:
1. Use promise.all() or axios.all() to execute request1 and request2 at the same time. So request2 will execute without waiting for request1 response. After request1 and request2 return the response, request3 will continue execute based on the returned response data as parameter.
2. Template Strings use back-ticks (``)
async componentDidMount(){
try{
const [request1, request2] = await Promise.all([
axios.get(`https://maps.googleapis.com/maps/api/geocode/json?&address=${this.props.p1}`),
axios.get(`https://maps.googleapis.com/maps/api/geocode/json?&address=${this.props.p2}`)
]);
const request3 = await axios.get(`https://maps.googleapis.com/maps/api/directions/json?origin=place_id:${request1.data.results.place_id}&destination=place_id:${request2.data.results.place_id}&key=${API-KEY-HIDDEN}`);
console.log(request3);
}
catch(err){
console.log(err)
}
}