Promises in React native - javascript

api/index.js
const URL = 'http://10.0.2.2:5000';
const fetching = false;
export default (type, filter, dateFilter, position) => {
if(fetching) return Promise.reject(new Error('Request in progress'));
fetching = true;
return fetch(URL + `/search/${type}/${filter}/${dateFilter}/${position}/0/0`)
.then(response => Promise.all([response, response.json()]))
.catch(err => console.log("error catch search:", err.message))
}
I need to put fetching false so in that way i can call this function again, but i dont know where to put it to make it work.
If i create another then like this after the then writen and before the catch like this:
.then(() => fetching = false)
The problem is that it returns false to the place the function is called and NOT the data this is where is called:
actions/index.js
getDataApi(type, filter, dateFilter, position)
.then(res => {
if (res !== false) {
if (state.dataReducer.data.length === 0) {
dispatch(getDataSuccess(res[1]))
} else {
dispatch(getDataSuccess(res[1], state.dataReducer.data))
}
}
})
.catch((err) => console.log(9999, err))
So my problem is that it doesnt enter in the getDataSuccess because is false.I dont know why it cannot send the data to this function and it ends sending the result of fetching = false.

You need another .then so that you can reassign fetching after the response.json() resolves. You should also probably reassign fetching in the catch so that future requests are possible even if there's an error once, and return false in the catch so the .then after getDataAPI will properly ignore failed requests. Also, use let rather than const for fetching:
const URL = 'http://10.0.2.2:5000';
let fetching = false;
export default (type, filter, dateFilter, position) => {
if (fetching) return Promise.reject('Request in progress');
fetching = true;
return fetch(URL + `/search/${type}/${filter}/${dateFilter}/${position}/0/0`)
.then(response => Promise.all([response, response.json()]))
.then(([response, responseObj]) => {
fetching = false;
return [response, responseObj];
})
.catch(err => {
console.log("error catch search:", err.message);
fetching = false;
// Choose one, depends what you need.
return false; // If you want to ignore the error and do something in a chained .then()
return Promise.reject(err); // If you want to handle the error in a chained .catch()
})
}

Related

Proper way of dealing with returning from a fetch

I'm a bit new to coding in a JS/TS way and I just wanted to know the best practice when it comes to returning and handling void and values that come from a fetch. In short, I'd like to use fetch to retrieve a JSON file somewhere, extract some relevant info, and return a dict.
async function doSomething() {
const response = fetch(...)
.then(response =>
response.json().then(data => ({
data: data,
response: response.ok
}))
)
.then(data => {
if (!data.response) {
console.warn("Response was not ok...")
return null
} else if (data.data["results"] == 0) {
console.info("Returned no results")
return null
} else {
const returned = {
name: data.data["stuff"],
thing: data.data["other"]
}
return returned
}
})
.catch(error => console.error(`${error}`))
return response
TS returns an error saying that Property 'name' does not exist on type 'void | {...} when I want to use the values of the dict. The error, I completely understand. When using the function I try to do type checking to handle when it returns void, but it still raises an error for something like this:
const request = await getQuery("movie", query)
if (request === undefined || request === null) return "I wasn't able to find your query."
const data = {
name: request.name
}
}
I'm just wondering what's the best way to write and handle void, and using the dict values.
I wouldn't have the function do too much. Have it concentrate on returning some data, and let the function that calls it deal with how that data is going to be used.
If you're going to use async/await you should be consistent. Mixing async with then doesn't make a lot of sense. This way you're either going to return some data, or throw an error.
async function getData(endpoint) {
try {
const response = await fetch(endpoint);
if (response.ok) {
const { data } = await response.json();
return data;
} else {
throw new Error('Response error.');
return undefined;
}
} catch (err) {
console.warn(err);
}
}
async function main() {
const endpoint = 'http://example.com';
const data = await getData(endpoint);
if (data && data.results) {
console.log(data.results.name);
} else {
console.warn('No results');
}
}
main();

How to get data from Promise function

I have a problem don't know why i can't get return data from the function on another file, here what i try
my file.js
const psm = require("../services/psm");
psm.show(12).then((res) => console.log(res));
my service.js
const axios = require("../plugins/axios").default;
const module = "psm";
exports.show = async (payload) => {
await axios
.get(`/${module}/${payload}`)
.then((res) => {
return res.data.data;
})
.catch((err) => {
return Promise.reject(err.response);
})
.finally(() => {});
};
i get undefined return..
Problems in your code:
show function doesn't explicitly returns anything; as a result, promise returned by the show function is fulfilled with the value of undefined
Improvements that can be made in your code:
catch and finally blocks are not needed; catch block is unnecessary because rejected promise returned as a result of catch block will need to be handled by the code that calls the show function.
You will need the catch method or block in the calling code anyways. So, just remove the catch block and allow the calling code to catch and handle the error
show function doesn't needs to be async. You can just return the result of axios.get or axios.get(...).then(...)
Final version of "show" method:
exports.show = (payload) => {
return axios
.get(`/${module}/${payload}`)
.then((res) => {
return res.data.data;
});
}
You can call this function as:
psm.show(12)
.then(res => console.log(res))
.catch(error => { /* handle the error */ });
Alternate version of show function:
exports.show = (payload) => {
return axios.get(`/${module}/${payload}`);
}
You can call this version of show function as:
psm.show(12)
.then(res => console.log(res.data.data))
.catch(error => { /* handle the error */ });

Why does a chained promise's .then() runs after the prior promise failed with .catch()? [duplicate]

This question already has answers here:
Chained promises not passing on rejection
(4 answers)
Closed 1 year ago.
I have three functions functionA, functionB, and functionC.
Why does the .then(id)... block inside functionC run even though functionB throws an error and ends with the catch statement.
I'm sure I'm missing something important about promises.
const functionA = () => {
return fetch("http://localhost:3001/types")
.then((response) => response.json())
.then((data) => data)
.catch((error) => error);
};
const functionB = (type) => {
return functionA()
.then((response) => response.filter((item) => item.name === type))
.then((result) => {
if (result.length !== 1) { // assume for this example this is truthy
const error = new Error("no type found or found more than one");
throw error;
} else {
return result[0].id;
}
})
.catch((error) => error); // this runs as expected since we're throwing an error above
};
const functionC = (x, y) => {
return functionB(y)
.then((id) => { //why does this block run?
//..do something
})
.catch((error) => console.log("functionB threw an error"));
};
Your catch handler converts rejection into fulfillment with the error value. Just remove the .catch((error) => error); entirely, so that the rejection propagates to the caller.
This (which is basically what you have, just spread across two functions):
doSomething()
.then(x => { /* ...do something with x...*/ })
.catch(error => error)
.then(y => { /* ...do something with y...*/ });
is roughly analogous to this synchronous code:
let y;
try {
const x = doSomething();
y = /* ...do something with x... */;
} catch (error) {
y = error;
}
/* ...do something with y... */;
Catching the error and then completing normally suppresses the error.
In general, non-async code using promises should do one of two things:
Handle the error locally — this is usually only top-level entry points like your main function (if you have one) or event handlers.
Return the result of calling then without using catch, so that rejections propagate to the outermost level (where, hopefully, they're handled because of #1 above).
FYI, that's basically what async/await does automatically for you (ignoring a lot of details). Just for what it's worth, here's that code (slightly modified) using async/await, assuming functionC is the top-level entry point where errors should be handled:
const functionA = async () => {
const response = await fetch("http://localhost:3001/types");
if (!response.ok) { // (You're missing this check)
throw new Error(`HTTP error ${response.status}`);
}
return response.json();
};
const functionB = async (type) => {
const result = (await functionA()).filter(item => item.name === type);
if (result.length !== 1) {
const error = new Error("no type found or found more than one");
throw error;
}
return result[0].id;
};
const functionC = async (x, y) => {
// I'm assuming this is your top-level entry point, so we'll handle
// errors here
try {
const id = await functionB(y);
//..do something
} catch (error) {
console.log("functionB threw an error");
}
};

Upgrade .then .catch to async await and try catch

I'm tryng to upgrade this code for a better maintenance, this code uploads two images to a server, i know it's possible to get rid of those .catch, by applying async await functions, and try catch blocks, but it's pretty confusing for me, any help will be apreciated.
this._uploadService.makeFileRequest(Global.url + "/upload-image1/" + response.product._id, [], this.filesToUpload1, 'image')
.then((result: Product) => {
this.filesToUpload1 = null;
this._uploadService.makeFileRequest(Global.url + "/upload-image/" + response.product._id, [], this.filesToUpload, 'image')
.then((result: Product) => {
this.filesToUpload = null;
setTimeout( () => this._router.navigate(['/detail', this.saveProduct._id]), 800 );
})
.catch(err => {
console.log(err);
this._router.navigate(['/detail', this.saveProduct._id]);
})
})
.catch(err => {
console.log(err);
this._router.navigate(['/detail', this.saveProduct._id]);
})
I suggest using a pen and paper to draw a block diagram for the logic involved, i.e. which api gets called first, with what kind of data, then which api comes afterwards; also include any logical conditionals through branching.
After that, you should attempt to write something like
const aggregateFunction = async() => {
try {
const someResponse = await callFirstApi(); // return response
await callSecondApi(someResponse); // use the response of the first api for the second api
if (someConditional) {
await callThirdApi(); // response not returned (i.e. when not required)
}
} catch (error) { // catch all errors from all await if they're not within another try-catch
console.log(error);
}
}
This pattern should eliminate all then and catch blocks. If you need more specific error handling for calling say a specific api, wrap function call inside another try-catch block, but everything should still be within the outer try-catch so that all errors will be caught regardless.
this._uploadService.makeFileRequest = function(){
return new Promise(resolve => {
// do logic of file request
resolve(true);
})
}
var waitForTime = function() {
return new Promise(resolve => {
setTimeout( () => {
this._router.navigate(['/detail', this.saveProduct._id]),
resolve(true)
}, 800 );
})
}
var f = async function(){
try {
await this._uploadService.makeFileRequest(Global.url + "/upload-image1/" + response.product._id, [], this.filesToUpload1, 'image');
await this.fileToUpload1 = null;
await this._uploadService.makeFileRequest(Global.url + "/upload-image/" + response.product._id, [], this.filesToUpload, 'image')
await this.fileToUpload = null;
await waitForTime();
}
catch(e) {
// error logic
}
}
if (this.filesToUpload1 && this.filesToUpload) {
f()
}
this might be another cleaner approach with async,await and promise

Correct usage of Promises, Fetch, success/fail handlers

I want to be sure I'm using Promises correctly. We have the below method to simplify making API requests. I've removed things not necessary, like headers.
The intention here is to return a promise to the caller of makeApiRequest. This is being used in the context of a thunk (specifically redux-thunk) and we want to be able to chain more .then() statements.
const makeApiRequest = (request, onSuccess = defaultOnSuccess, onFailed = defaultOnFailed) => {
const CSRF_TOKEN = $('meta[name="csrf-token"]').attr('content')
const headers = { ... }
return fetch(request.url, {...}).then(response => {
if (response.ok) {
return response.json()
.then((json) => Promise.resolve(onSuccess(response.status, json)))
.catch((error) => Promise.reject({message: error, status: response.status}))
}
const errorResponse = {
status: response.status,
message: response.error
}
if(response.status === 401) {
errorResponse.message = 'Unauthorized'
}
return Promise.reject(errorResponse)
}).catch((error) => {
onFailed(error.status, error.message)
console.log(error)
})
}
const defaultOnFailed = (status, error) => console.log([status, error])
const defaultOnSuccess = (status, data) => console.log([status, data])
export default makeApiRequest
Questions
1) Am I implementing success/fail handlers optimally?
2) I feel like having the nested catch statements is wrong, but I need to be able to deal with errors in context.

Categories