This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I am trying to store the actual response from a Promise to a variable
let token;
let tokenPromise = new Promise(function(resolve, reject) {
fetch(tokenUrl, options)
.then(res => {
if (res.ok) {
return res.json()
} else {
reject('Not clean')
}
}).then((data) => {
resolve(data.access_token)
})
})
token = tokenPromise.then(res => {return res})
return token
When this is run, token returns as the Promise object and not the actual response. How do I store the actual response or a value from the response as a variable within the parent function?
Because the function then returns a promise.
An alternative is to use an async function.
function getToken() {
let tokenPromise = new Promise(function(resolve, reject) {
setTimeout(function() {
resolve('myNewToken');
}, 100);
});
return tokenPromise;
}
async function main() {
let token = await getToken();
console.log(token);
}
main();
Why you create a new Promise around fetch?
function status(res) {
if (res.ok) {
return Promise.resolve(res)
} else {
return Promise.reject(new Error(res.statusText))
}
}
function json(res) {
return res.json()
}
function getToken() {
return fetch(tokenUrl, options) // Fetch URL
.then(status) // Is everything nice?
.then(json) // Response to json
.then(jsonData => jsonData.access_token) // return access_token
.catch(function(error) { // Some S*ht Happens :(
console.log('Request failed', error);
/* ErrorHandling Stuff */
});
}
You could use ES7 async/await
let token;
let tokenPromise = async () => {
try {
const res = await fetch(tokenUrl, options);
const data = await res.json();
return data.access_token
} catch (error) {
console.error('Error fetching token', error);
return 'Not clean';
}
}
token = tokenPromise().then(res => res);
return token;
I'd create a method called get token first.
Updated/simplified based off 4castle's suggestion
getToken() {
return fetch(tokenUrl, options)
.then(res => res.json())
.then(data => data.access_token)
}
Then inside the method you'd like to use the token
someMethod() {
getToken().then(token => {
// Use it.
})
}
Related
I am trying to refactor this code using try-catch blocks:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
}).catch(error => console.log(error));
}
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
}).catch(error => console.log(error));
}
However I'm not getting the same result - the asynchronousity seems to be being handled differently. Here is my attempt at refactoring:
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxxxx",
'firebase_phone[access_token]': accessToken,
};
await createSession();
try {
ConnectyCube.login(userCredentials, (error, user) => {
return user;
})
}
catch (error) {
console.log(error)
}
}
const createSession = () => {
try {
ConnectyCube.createSession((error, session) => {
return session.user
})
} catch (error) {
console.log(error);
}
}
Is there any particular part of what I'm wrong? Thanks.
Callback-based APIs don't readily turn into something you can use for async/await (which under the hood uses promises). You'll have to "promisify" them first (i.e. wrap them in promises).
Here's an example of what I'm trying to say:
// Promisify these callback-based APIs.
const login = userCredentials => {
return new Promise((resolve, reject) => {
ConnectyCube.login(userCredentials, (error, user) => {
user ? resolve(user) : reject(error);
})
})
})
const createSession = () => {
return new Promise((resolve, reject) => {
ConnectyCube.createSession((error, session) => {
session ? resolve(session.user) : reject(error)
})
})
})
// Then use them in an async function
export const authorizeConnectyCube = async (accessToken) => {
const userCredentials = {
provider: 'firebase_phone',
'firebase_phone[project_id]': "xxxxxxxx",
'firebase_phone[access_token]': accessToken,
}
try {
await createSession()
return login(userCredentials)
} catch (e) {
console.warn(e)
}
}
Also, async functions return promises, with the resolved value being the return value, and the rejected value being any uncaught error thrown inside. A value wrapped in a promise as return value for an async function is redundant.
If you're using Node 8+, it has a utility called promisify which accepts a callback-based API and returns a promise-returning version of it.
My code is violating the eslint rule no-async-promise-executor but I'm not sure how to refactor it so that it doesn't have the async in the new Promise(async (resolve, reject) => {});. My code is full of these and I guess it causes errors to bot be caught so I could use some help understanding how to approach this better.
Here's an exampe function:
updateUser = () => {
return new Promise(async (resolve, reject) => {
try {
const url = "/getUser";
const response = await fetch(url);
if (response.ok) {
const user = await response.json();
//
// Do something with user object...
//
} else {
console.log("response", response);
window.location = "/admin";
}
resolve();
} catch (error) {
console.log("error: ", error);
reject(error);
}
});
};
when you mark the function as async, it will automatically wrap the return value inside a promise, whatever you return from the function... it will get passed to .then() and whatever is thrown inside a async function will get passed to your error handler such as .catch()
here is a example of what you could do.
const updateUser = async () => {
const url = "/getUser";
let response;
try {
response = await fetch(url);
} catch (error) {
throw new Error(error);
}
return response;
}
you can also reference the global promise explicit to return or reject values inside a async function.
const updateUser = async () => {
const url = "/getUser";
let response;
try {
response = await fetch(url);
} catch (error) {
Promise.reject(error);
}
return Promise.resolve(response);
}
async functions always return promises.
By wrapping your anonymous async function in new Promise(...) you are creating a Promise which only and always adopts the promise returned by the async function.
Just get rid of the wrapper, replace your resolve calls with return and your reject with throw.
updateUser = async () => {
try {
const url = "/getUser";
const response = await fetch(url);
if (response.ok) {
const user = await response.json();
//
// Do something with user object...
//
} else {
console.log("response", response);
window.location = "/admin";
}
} catch (error) {
console.log("error: ", error);
throw error;
}
};
I have quite an issue for some time and is getting on my nerves and it doesn't make sense. I have used axios on my react frontend and it works perfect when assigning the get value to the state. But when using it in a normal javascript code, I appear to have this following issue: i can print the object's value in the console but it will return only undefined.. Here is my code:
login = () => {
let data;
axios.get('https://myaddress/authenticate')
.then(response => {
data = response;
console.log('data here', data);
})
.catch(error => {
console.error('auth.error', error);
});
console.log('eee', data);
return data;
};
Here we are talking about axios strictly.
You can't return an ajax response because it's asynchronous. You should wrap your function into a promise or pass a callback to login
UPDATE: As #Thilo said in the comments, async/await would be another option, but it will let you set the response to data tho ...
1. Wrap into a promise
login = () => new Promise((resolve, reject)=>{
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
});
});
// Usage example
login()
.then(response =>{
console.log(response)
})
.catch(error => {
console.log(error)
})
2. Pass a callback
login = (callback) => {
axios.get('https://myaddress/authenticate')
.then(response => {
callback(null,response)
})
.catch(error => {
callback(error,null)
});
};
// Usage example
login((err, response)=>{
if( err ){
throw err;
}
console.log(response);
})
3. Async/Await
login = async () => {
// You can use 'await' only in a function marked with 'async'
// You can set the response as value to 'data' by waiting for the promise to get resolved
let data = await axios.get('https://myaddress/authenticate');
// now you can use a "synchronous" data, only in the 'login' function ...
console.log('eee', data);
return data; // don't let this trick you, it's not the data value, it's a promise
};
// Outside usage
console.log( login() ); // this is pending promise
In ES7/ES8 you can do async/await like a boss:
login = () => {
return new Promise((resolve, reject) => {
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
console.error('auth.error', error);
reject(error)
});
});
};
async function getData() {
try{
const data = await login()
} catch(error){
// handle error
}
return data;
}
getData()
.then((data) => console.log(data));
I'm in the process of converting some functions to async await and need help to solve an error.
Before
const getRequest = (url, headers) => {
return new Promise((resolve, reject) => {
axios.get(url, { headers })
.then((res) => {
return resolve(res);
})
.catch((err) => {
return reject(err);
});
});
After
async function getRequest(url, headers) {
return new Promise(resolve, reject) {
try {
const res = await axios.get(url, { headers })
return resolve(res);
}
catch(err){
return reject(err);
};
};
};
I'm getting an error when running the new code, any help would be appreciated.
First of all, your original code is badly indented, so let's fix that:
const getRequest = (url, headers) => {
return new Promise((resolve, reject) => {
axios.get(url, { headers })
.then((res) => {
return resolve(res);
})
.catch((err) => {
return reject(err);
});
});
Secondly, your original code contains a whole lot of unnecessary code because axios.get is already a promise. This shows lack of understanding on how promises work, please read this list of anti-patterns. You should just return the promise directly. Fixing that:
const getRequest = (url, headers) => {
return axios.get(url, { headers });
});
Thirdly, converting a function to async, when the function already returns a promise, means nothing more than simply adding the async keyword itself. You do not have to do anything to the function. Final result:
const getRequest = async (url, headers) => {
return axios.get(url, { headers });
});
async function getRequest(url, headers) {
const res = await axios.get(url, { headers })
return res;
};
First of all you have got a syntax error in declaring a promise.
The getRequest function should look something like this -
async function getRequest(url, headers) {
return new Promise((resolve, reject) => {
try {
const res = await axios.get(url, { headers })
return resolve(res);
}
catch (err) {
return reject(err);
};
});
};
Second, id axios.get(url, { headers }) is waiatable, you do not need to return a promise from the parent funtion.
You can simply return await axios.get(url, { headers });
async function getRequest(url, headers) {
return await axios.get(url, { headers });
};
Example
async function parent() {
console.log(await child(true));
}
function child(data) {
return new Promise((resolve, reject) => {
if (!!data) {
resolve("resolved!");
} else {
reject("rejected!");
}
});
}
parent();
Due to the api of a plugin I'm using not working properly. I need to merge the two different requests. I am using the thunk below.
I can get a response but I cannot seem to check for response.ok, and return the combined data:
export function fetchCategories() {
const firstPage =
"http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page=1";
const secondPage =
"http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page=2";
return dispatch => {
dispatch(isLoading(true));
Promise.all([fetch(firstPage), fetch(secondPage)])
.then(response => {
// check for ok here
response.ForEach(response => {
if (!response.ok) throw Error(response.statusText);
});
dispatch(isLoading(false));
return response;
})
.then(response => response.json())
// dispatch combined data here
.then(data => dispatch(fetchSuccessCategories(data)))
.catch(() => dispatch(hasErrored(true)));
};
}
Any ideas?
You are doing the check for .ok fine because it's in a loop, but your response is actually an array of two Response objects, it does not have a .json() method. You could do Promise.all(responses.map(r => r.json())), but I would recommend to write a helper function that does the complete promise chaining for one request and then call that twice:
function fetchPage(num) {
const url = "http://wordpress.rguc.co.uk/index.php/wp-json/tribe/events/v1/categories?per_page=60&page="+num;
return fetch(url).then(response => {
if (!response.ok)
throw new Error(response.statusText);
return response.json();
});
}
export function fetchCategories() {
return dispatch => {
dispatch(isLoading(true));
Promise.all([fetchPage(1), fetchPage(2)]).then(data => {
dispatch(isLoading(false));
dispatch(fetchSuccessCategories(merge(data)));
}, err => {
dispatch(isLoading(false));
dispatch(hasErrored(true));
});
};
}