Handling promises while having setinterval - discord.js

Sorry if title was a bit unclear, what I want to do is catch the member.send, but I don't know how to use try and catch when also using timeinterval. It gives me an error saying that I haven't handled it.
message.guild.members.forEach(member => {
try {
setInterval(() => {
member.send("hello");
}, 2000)
}
catch(e) {
console.log("couldnt send dm to a user!");
}
Second problem: Cannot read property of 'guild' of undefined, and UnhandledPromiseRejection
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// create an async function and run it
(async function(message) {
for (const [id, member] of message.guild.members) {
try {
// await will throw any error found and allow try/catch to work
await member.send("hello");
} catch (err) {
console.log("Found error", err);
}
await sleep(2000);
}
})();

try/catch doesn't work for promise rejections, nor does it work when wrapped around a setInterval. Just catch the promise:
member.send("hello").catch(err => {
console.error(`Got error ${err}.`);
});
If you want to send a message to each person then the best way is to use a promise-based sleep function:
function sleep(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}
// create an async function and run it
(async function() {
for (const [id, member] of message.guild.members) {
try {
// await will throw any error found and allow try/catch to work
await member.send("hello");
} catch (err) {
console.log("Found error", err);
}
await sleep(2000);
}
})();

Related

React Promise All Multiple APIs, Different Error Handling

I wanted to run different error handling with React Promise.
API 1 and 2 should have different error handlings.
Execute APIs all at once to save time.
Run different error handling statements for each API as soon as possible, without waiting for the others.
Each API should continue even if one fails.
How can this be done?
Reference:
Fetch API requesting multiple get requests
Promise.all([
fetch(api1).then(value => value.json()),
fetch(api2).then(value => value.json())
])
.then((value) => {
console.log(value)
//json response
})
.catch((err) => {
console.log(err);
});
Promise.all is just wrapping up whatever promises you give it - so there's no reason you couldn't handle the errors separately for each one. For example, you could create a separate function for each of the fetches - you could even throw a custom error here that dictates some sort of "followUp" action to do, or identifies where the error is from, or anything (you can throw anything in javascript):
const fetchFromApi1 = async () => {
try {
const response = await fetch(api1);
return response.json();
} catch (err) {
console.log('API 1 failed');
// Throw a custom error
throw {
errorSource: 'API_CALL_1',
message: 'API call 1 failed',
};
}
};
const fetchFromApi2 = async () => {
// ----- 8< -----
};
Then you can just combine them in your your Promise.all - if you've thrown a custom error as above, you can use that to work out what to do:
const fetchAllTheThings = async () => {
try {
const [response1, response2] = await Promise.all([
fetchFromApi1(),
fetchFromApi2(),
]);
} catch (err) {
const { errorSource, message } = err;
// do something....
}
};
Edit
If you want to know which promise failed at the point of calling, you're probably better off using allSettled -
const fetchAllTheThings = async () => {
const [result1, result2] = await Promise.allSettled([
fetchFromApi1(),
fetchFromApi2(),
]);
if (result1.status === 'rejected') {
// Sad for promise 1
}
if (result2.status === 'rejected') {
// Sad for promise 2
}
};
const p1 = new Promise((res, rej) => {
setTimeout(() => {
res("p1 success")
}, 1000)
})
const p2 = new Promise((res, rej) => {
setTimeout(() => {
res("p2 success")
}, 3000)
})
const p3 = new Promise((res, rej) => {
setTimeout(() => {
rej("p3 failed")
}, 1000)
})
const p4 = new Promise((res, rej) => {
setTimeout(() => {
rej("p4 failed")
}, 2000)
})
Promise.allSettled([p1, p2, p3, p4])
.then(console.log)

Rejecting from Promise.all

I have an aysnc function that fetches data and returns the value of Promise.all i.e.
const fetchDownloadMenuData = async selectedItems => {
return Promise.all(
selectedItems.map(async item => {
try {
if (item.id === 'interviewGuide') {
const interviewGuide = await positionCandidatesService.getCandidate(
positionId,
candidateSelected.id
);
return interviewGuide.interviewGuide;
}
if (item.id !== 'overview' && item.id !== 'profile') {
const outcome = await outcomesService.get(candidateSelected.id, item.id);
return outcome;
}
return null;
} catch (err) {
appInsights.trackException({
error: new Error(`Error fetching candidate outcome: ${JSON.stringify(err)}`)
});
return null;
}
})
)};
I call this function like this:
try {
downloadData = await fetchDownloadMenuData(selectedItems);
} catch (err) {
appInsights.trackException({
error: new Error(`Could not fetch all PDF data: ${JSON.stringify(err)}`)
});
return;
}
But it never goes into the catch. Why is this? How do i get it to reject if all the promises don't resolve?
Thanks
You're not rejecting in the map...catch block, instead you're returning the null. That's why Promise.all not able to catch the exception. You need use throw in the catch block, Remember, throw will terminate the execution flow.
Try like this
selectedItems.map(async item => {
try {
...async stuff
} catch (err) {
appInsights.trackException({
error: new Error(`Error fetching candidate outcome: ${JSON.stringify(err)}`)
});
throw err OR throw new Error(err) <-- this is missing earlier.
}
})

Can't perform a React state update on an unmounted component even with axios cancel token in place

I am using an Axios cancel request which I thought was to prevent this error yet I am still getting it. Basically I enter a screen where it is fetching data from the server. If I go back to the previous screen before it has finished loading I get the error.
useEffect(() => {
const ourRequest = Axios.CancelToken.source();
setLoading(true);
const getPub = async () => {
try {
const response = await Axios.get("https://.....", {
cancelToken: ourRequest.token,
});
if (response.data) {
const info = await Axios.get(
'http://anotherurl', {
cancelToken: ourRequest.token,
});
setPub(pubInfo.data);
setLoading(false);
}
} catch (err) {
setError(err);
setLoading(false);
}
};
getPub();
return () => {
ourRequest.cancel();
};
}, []);
The request was successfully canceled and it will go to catch block, however the catch block performed a setState "setLoading(false)" but the component was already unmounted. You may performed a condition on catch block to check if the request was canceled.
try {
...
} catch (err) {
if(!request is canceled){
setError(err);
setLoading(false);
}
}

How can I use async / await functions?

I have a function as follows:
function getMessages(){
this.removeListener = myFirestore
.collection('messages')
.doc(this.groupChatId)
.collection(this.groupChatId)
.onSnapshot(
snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type === 'added') {
this.listMessage.push(change.doc.data())
}
})
},
err => {
console.log(err)
}
)
return this.renderMessages() # my function
}
In above function I need to use this.listMessage array in this.renderMessages() function.For that getMessages() function should execute my firestore query first and then this.renderMessages() function should be called.But without executing firestore query this.renderMessages() is being called.I know this is the issue with async / await functions but I don't know much about those functions.
Now how can I call this.renderMessages() function after the firestore query by using async / await functions?
You can try this type of approach for using async/await.
async function getMessage() {
try {
this.removeListener = await myFirestore
.collection("messages")
.doc(this.groupChatId)
.collection(this.groupChatId)
.onSnapshot(snapshot => {
snapshot.docChanges().forEach(change => {
if (change.type === "added") {
this.listMessage.push(change.doc.data());
}
});
});
} catch (error) {
console.log(error);
}
return this.renderMessages();
}
The code above waits for myFirestore and then returns rendermessage. The keyword await makes JavaScript wait until that promise settles and returns its result. Hope this helps. If ypu want to catch error then you can use try..catch block

Jest: toThrow() matcher

Context: React application with mobx.
Anyway I've a class (a store), catalogStore, with a loadProducts method. This method call a service to get the data and then, return it.
I've to write a test that say "If it cannot get the data, then throw an exception"
I mocked the function supposed to get the data, forcing it to reject... ok
This is the test I wrote
describe("catalogStore", () => {
describe("if the catalog fails to get the data", () => {
beforeAll(() => {
catalogService.get = jest.fn().mockImplementation(() => {
return new Promise((resolve, reject) => {
reject("rejected error");
});
});
});
it("should throw an error", () => {
return expect(() => catalogStore.loadProducts()).toThrow();
});
});
});
And this is the loadProducts function:
loadProducts() {
return catalogService
.get()
.then(result => {
this.products = result.services;
return {products: this.products};
})
.catch(error => {
console.log("CatalogStore loadProducts error catch: ", error);
return { error };
})
.then(({ error }) => {
if (error) {
console.log("Im gonna throw the error -> ", error);
throw error;
}
});
}
From the logs I can see "Im gonna throw the error -> rejected error", but the test fails with this message:
Expected the function to throw an error. But it didn't throw anything.
Why? I'm throwing the error.
Luca
Your error is thrown in the context of a Promise chain callback. It will be caught by the Promise and passed to the next catch handler.
To modify your test to inspect the error you could use Jest's Promise expectations:
describe("catalogStore", () => {
describe("if the catalog fails to get the data", () => {
beforeAll(() => {
catalogService.get = jest.fn().mockImplementation(() => {
return new Promise((resolve, reject) => {
reject("rejected error");
});
});
});
it("should throw an error", () => {
return expect(catalogStore.loadProducts()).rejects.toThrow('rejected error');
});
});
});
Its cause the function returns a promise, so all jest see is that the get() function is the called but as the error happens in a promise the test is finished before the error is thrown. To test that promises have look on how async error handling works.
Main idea is that you have an async function where you catch the failing promises by yourself
it('fails', async()=>{
try{
await catalogStore.loadProducts()
} catch(e) {
expect(e).toBeDefined()
}
})

Resources