I'm making a support command: you type a command, the bot send you a message and then you reply to that message. I've used the awaitMessages function but it doesn't work.
case `support` : {
message.channel.send("What's your problem?");
let filter = m => m.author.id === message.author.id;
let msg = await message.channel.awaitMessages(filter, {maxMatches: 1});
message.channel.send("Your problem is: " + msg.first().content);
break;
}
To use .then() you need to return a Promise. This is a basic example of how you can use Promise:
const myFunction = () => {
return new Promise((resolve, reject) => {
if(taskIsSuccesFullyDone)
{
resolve(true); // Pass anything
}else{
reject('Something went wrong!');
}
});
}
myFunction().then(() => {
// Task is succesful completed.
// Do anything
})
.catch(error => console.log(error.message || error));
In your case, your code would look something like this:
function support_message() {
return new Promise((resolve, reject) => {
message.author.send(`Hello, <#${message.author.id}>, reply to this message explaining the problem you have.`)
.then(message => resolve(message))
.catch((error) => {
message.reply("I can't send you messages, be sure that you allow direct messages from unknown users to use this command.");
reject(error);
})
});
}
case `staff-support` : {
support_message().then(message => {
// We got the message object passed from the resolved Promise
// Do anything here
})
.catch((err) => {
// There was a problem!
// Do anything here.
});
break;
}
Related
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)
In my react project,
I have two states, one is Projection, other is called StressProjections
I have a function that will invoke two Api call, once the api return come back. It will update both state
Below is my code.
//call Api 1
axios
.post<IProjectionResponse>(`/api1`, normalProjectionRequest)
.then(res => {
const result = res.data.result
props.setProjection(result)
})
.catch(error => {
console.log(error)
})
//call Api 2
axios
.post<IStressProjectionResponse>(
`api2`,
stressProjectionRequest
)
.then(res => {
const result = res.data.result
props.setStressProjections(result)
})
.catch(error => {
console.log(error)
})
However, I notice that my StressProjections is always set with "" , empty value. But I am sure the api 2 call is valid, and the return does have something in it. But after rendering, only state Projection have response data in it, but no data in state StressProjections
So my suspicion is that you update a piece of state and rerender the component before the other request is done, but it is hard to tell without seeing the rest of the code.
Try this and see if it solves your issue (post more code if not):
const promise1 = axios.post<IProjectionResponse>(`/api1`, normalProjectionRequest)
const promise2 = axios.post<IStressProjectionResponse>(`api2`,stressProjectionRequest)
Promise.all([promise1, promise2])
.then(values => {
props.setProjection(**VAL HERE**)
props.setStressProjections(**VAL HERE**)
})
.catch(err => {
console.log(err)
})
For the future, it is generally better practice to package multiple requests in a Promise all, this way you have to write way less code for error handling etc.
If you need to know which promise failed:
const promise1 = new Promise((resolve, reject) => {
axios
.get("https://api.github.com/users/niklasbec")
.then((data) => {
resolve(data);
})
.catch((err) => {
reject(err);
});
});
const promise2 = new Promise((resolve, reject) => {
axios
.get("https://api.github.com/users/noneexistinguser123")
.then((data) => {
resolve(data);
})
.catch((err) => {
reject(err);
});
});
Promise.allSettled([promise1, promise2]).then((vals) => {
console.log(vals);
vals.forEach((val, index) => {
if(val.status === "rejected") {
if(index === 0) {
//ERROR handling 1
console.log("error in promise 1")
} else {
//ERROR handling 2
console.log("error in promise 2")
}
}
})
});
This will let you do whatever you want with the error handling, hope that helps.
BTW: If you are wondering why I am wrapping the axios promise in another promise, I have to resolve manually so I can pass the response value of the request, maybe axios has a native way to do it but I don't know of one. Anyway, it works.
I am having a case now with websockets.
I am using Promise to read response and message from socket. Afterwards I compare them and if they have the same id, it goes through.
However, most of the time socket message is arriving (fast) before response and as a result I cannot compare socket message with response id.
const init = {
get(...args) {
return request.get(...args);
},
post(...args) {
// return request.post(...args)
return new Promise((resolve, reject) => {
let response = {};
request
.post(...args)
.then((res) => {
console.log("RESPONSE====>", res);
response = res;
})
.catch((err) => reject(err));
webSocket.onmessage = (mes) => {
try {
// console.log(JSON.parse(mes.data))
let { correlation_id: socketId, status_code } = JSON.parse(mes.data);
console.log("MESSAGE====>", socketId);
if (socketId === response.message) {
resolve(response);
} else if (status_code > 300) {
reject({ status_code });
}
} catch (e) {
console.log(e);
}
};
// resolve(response)
});
}
export default init;
Above is my code for axios requests. If you know how to resolve it, kindly help here.
I cam across a strange thing which I don't quite get it.
I have a listener on event newOrder which should be received every time when a newOrder is emitted from backend. The problem here is that if I use it like this useEffect(() => { ... }, []) it will fire only once which somehow make sense but if I use it like useEffect(() => { ... }) it fires too many times because of the new renders.
My question is how is best to use it in a useEffect to listen every time when a newOrder is received, or is there a better approach?
Here is my code
useEffect(() => {
// WAIT FOR A NEW ORDER
ws.on('newOrder').then(data => {
dispatch(addOrder(data));
dispatch(updateStatus('received'));
});
// CLIENT CANCELED
ws.on('clientCanceledOrder').then(() => {
dispatch(updateStatus('ready'));
dispatch(clearPrice());
alert('Your rider has canceled the order!');
});
return () => {
ws.off('newOrder');
ws.off('clientCanceledOrder');
};
}, []);
Here is my SocketClient.js
export default class socketAPI {
socket;
connect(user) {
this.socket = io(BASE_URL, {
query: `type=driver&id=${user}`,
reconnection: true,
transports: ['websocket', 'polling'],
rememberUpgrade: true,
});
return new Promise((resolve, reject) => {
this.socket.on('connect', () => {
console.log(this.socket.io.engine.id);
resolve(true);
});
this.socket.on('connect_error', error => reject(error));
});
}
disconnect() {
return new Promise(resolve => {
this.socket.disconnect(reason => {
this.socket = null;
resolve(false);
});
});
}
emit(event, data) {
return new Promise((resolve, reject) => {
if (!this.socket) {
return reject('No socket connection. Emit Event');
}
return this.socket.emit(event, data, response => {
// Response is the optional callback that you can use with socket.io in every request.
if (response.error) {
return reject(response.error);
}
return resolve(response);
});
});
}
on(event) {
// No promise is needed here.
return new Promise((resolve, reject) => {
if (!this.socket) {
return reject('No socket connection. On event');
}
this.socket.on(event, data => {
resolve(data);
});
});
}
off(event) {
// No promise is needed here.
return new Promise((resolve, reject) => {
if (!this.socket) {
return reject('No socket connection. On event');
}
this.socket.off(event, data => {
resolve(data);
});
});
}
}
then I call this const socketClient = new SocketClient(); and this
`useEffect(() => {
(async () => {
const isConnected = await socketClient.connect(driver.id);
dispatch(updateSocketStatus(isConnected));
})();
}, [driver]);` inside my context
In general promise is resolved/reject only one time and then no more. But socket.io can emit more than one message. I suggest you to rework WS wrapper method to add event listener instead of promise
on(event, listener) {
if (!this.socket) {
throw 'No socket connection. On event';
}
this.socket.on(event, listener);
}
I have an action that is getting dispatched that is triggering multiple remote methods and returning'TALK_SUBMIT_REJECTED' The strange thing however, is that all of the data that I am getting is still returned and updating the store as expected.
I am however getting these two errors in the process:
xhr.js:178 POST http://localhost:3000/api/talks/talkSubmit 500
(Internal Server Error)
createError.js:16 Uncaught (in promise) Error: Request failed with
status code 500
at e.exports (createError.js:16)
at e.exports (settle.js:18)
at XMLHttpRequest.m.(:3000/anonymous function)
(http://localhost:3000/bundle.js:6:2169)
I have thrown in two dozen console.logs recording all of the data I am sending and receiving and everything returning as expected.
I apologize in advance for the long post but I have been struggling with this bug for a while.
to give a brief summery of what my code is doing:
I have a form that upon submission, triggers an action that starts a chain of remote methods.
This is the first method:
function talkSubmit(speakerInfo, talkInfo, date) {
return new Promise((resolve, reject) => {
const { Talk, Speaker, Event } = app.models;
return Speaker.create(speakerInfo)
.then(response => {
let speakerId = response.id
return getMeetups()
.then(meetups => {
const index = meetups.findIndex((item) =>
item.date == date);
let name = meetups[index].name;
let details = meetups[index].description;
let meetupId = meetups[index].meetupId;
if (index === -1)
return reject(new Error('NO meetup with that
date found!'));
return Event.findOrCreate({ date, name, details,
meetupId })
.then(event => {
let eventId = event[0].id
return Talk.create({ ...talkInfo,
speakerId, eventId })
.then(talk => resolve(talk))
.catch(err => console.log(err))
})
.catch(err => reject(err))
})
.catch(err => reject(err))
})
.catch(err => reject(err))
})
}
module.exports = { talkSubmit };
//this is the get meetups function that is called by talkSubmit
function getMeetups() {
return new Promise((resolve, reject) => {
let currentDate = new Date();
currentDate.setMonth(currentDate.getMonth() + 3);
const date ='${ currentDate.getFullYear() } -${
currentDate.getMonth() } -${
currentDate.
getDay()
} ';
axios.get(`https://api.meetup.com/sandiegojs/events?
no_later_than = ${ date } `)
return resolve(response.data.map(event => ({
meetupId: event.id,
name: event.name,
date: event.local_date,
time: event.local_time,
link: event.link,
description: event.description,
})))
.catch(err => reject(new Error('getMeetups failed to get SDJS
meetups')))
})
}
module.exports = { getMeetups };
//This is the after remote method that is triggered when talkSubmit is
//completed.
Talk.afterRemote('talkSubmit', function (ctx, modelInstance, next) {
const speakerId = ctx.result.speakerId;
const eventId = ctx.result.eventId;
const approved = false;
const pending = true;
formatTalkForEmail(speakerId, eventId)
.then((response) => {
const speakerName = response.speakerName;
const speakerEmail = response.speakerEmail;
const meetupTitle = response.meetupTitle;
const meetupDate = response.meetupDate;
sendEmailToSpeaker(process.env.ADMIN_EMAIL, approved,
pending, speakerEmail, speakerName, meetupTitle, meetupDate)
.then(() => next())
.catch(err => next(err));
})
.catch(err => next(err));
});
//this is the formatTalkForEmail method called in the remote method
function formatTalkForEmail(speakerId, eventId) {
return new Promise((resolve, reject) => {
if (speakerId == undefined) {
return reject(new Error('speakerId is undefined'));
}
if (eventId == undefined) {
return reject(new Error('eventId is undefined'));
}
const { Speaker, Event } = app.models;
Speaker.findById(speakerId)
.then(speaker => {
const speakerName = speaker.speakerName;
const speakerEmail = speaker.speakerEmail
return Event.findById(eventId)
.then(selectedEvent => {
const meetupTitle = selectedEvent.name;
const meetupDate = selectedEvent.date;
resolve({
speakerName,
speakerEmail,
meetupTitle,
meetupDate
})
})
.catch(err => reject( err ))
})
.catch(err => reject(err))
})
}
module.exports = { formatTalkForEmail };
//and finally this is the sendEmailToSpeaker method:
function sendEmailToSpeaker(adminEmail, approved, pending,
speakerEmail, speakerName, meetupTitle, meetupDate) {
return new Promise((resolve, reject) => {
let emailContent;
if (approved && !pending) {
emailContent = `Congratulations! Your request to speak at
${ meetupTitle } on ${ meetupDate } has been approved.`
}
if (!approved && !pending) {
emailContent = `We're sorry your request to speak at
${ meetupTitle } on ${ meetupDate } has been denied.`
}
if (pending) {
emailContent = `Thank you for signing up to speak
${ meetupTitle } on ${ meetupDate }.You will be notified as soon as
a
SDJS admin reviews your request.`
sendEmailToAdmin(adminEmail, meetupDate, meetupTitle,
speakerEmail, speakerName)
.catch(err => console.log(err));
}
const email = {
to: speakerEmail,
from: adminEmail,
subject: 'SDJS Meetup Speaker Request',
templateId: process.env.ADMIN_SPEAKER_EMAIL_TEMPLATE,
dynamic_template_data: {
emailContent: emailContent,
sdjsBtn: false,
title: 'SDJS Meetup Speaker Request'
}
}
sgMail.send(email)
.then(() => resolve({ email }))
.catch(err => {
console.log(err);
reject(err);
});
})
}
in conclusion I have no clue what part of talkSubmit is throwing those two errors and yet both emails are getting automatically sent and the store is updating with all the proper data despite the initial action creator returning rejected. I appreciate any help anyone can offer.
Ok so I think the main problem is here:
axios.get(`https://api.meetup.com/sandiegojs/events?no_later_than = ${ date } `)
return resolve(response.data.map(event => ({
meetupId: event.id,
name: event.name,
date: event.local_date,
time: event.local_time,
link: event.link,
description: event.description,
})))
it should look like that (I recommend to extract mapping method):
axios.get(`https://api.meetup.com/sandiegojs/events?no_later_than = ${ date} `)
.then( response => resolve(response.data.map(event => ({
meetupId: event.id,
name: event.name,
date: event.local_date,
time: event.local_time,
link: event.link,
description: event.description,
}))))
.catch(err => reject(new Error('getMeetups failed to get SDJS meetups')))
and a few words about Promises. You can chain them like that:
method()
.then(method2())
.then(method3())
.then(method4())
...
.catch(err =>...
also I don't understand why you wrap content of method in return new Promise((resolve, reject) => { I think is not needed in your case
so you can change talkSubmit method to something like that (this is just a draft, I recommend to extract methods from then blocks)
function talkSubmit(speakerInfo, talkInfo, date) {
const { Talk, Speaker, Event } = app.models;
return getMeetups()
.then(meetups => {
const index = meetups.findIndex((item) => item.date == date);
let name = meetups[index].name;
let details = meetups[index].description;
let meetupId = meetups[index].meetupId;
if (index === -1)
return reject(new Error('NO meetup with that date found!'));
return Promise.all([
Event.findOrCreate({
date, name, details,
meetupId
}),
Speaker.create(speakerInfo)])
})
.then(([event, speaker]) => {
let eventId = event[0].id
let speakerId = speaker.id
return Talk.create({
...talkInfo,
speakerId, eventId
})
})
}