I'm developing a chat application and so far i'm polling my server for messages every two seconds. To make the chat more instant i'd like to implement long polling. I'm trying to implement this JS.info Guide for it but i keep not hitting the goal i intend to hit. Can anyone point this out for my case?
I have a custom hook for this in react which is basic polling for now.
FYI: I'm a beginner and wont use WS or Socket.io now. It's too much for me at this point.
Thanks in advance!
export default function useGetChatMessages(_id) {
const [chatMessages, setChatMessages] = React.useState([]);
React.useEffect(() => {
const interval = setInterval(() => {
getChatMessages(_id).then(fetchedChatMessages => {
setChatMessages(fetchedChatMessages);
});
}, 2000);
return () => clearInterval(interval);
}, [_id]);
return chatMessages;
}
This is my server function with express. I guess it should be implemented here rather than in my hook
router.get('/:id/messages', async (request, response) => {
try {
const chat = await Chat.findById(request.params.id);
response.json(chat.messages);
} catch (error) {
console.log(error);
response.status(500).json({ message: error.message });
}
});
I'm developing a chat application and so far i'm polling my server for messages every two seconds. To make the chat more instant i'd like to implement long polling. I'm trying to implement this JS.info Guide for it but i keep not hitting the goal i intend to hit. Can anyone point this out for my case?
I have a custom hook for this in react which is basic polling for now.
FYI: I'm a beginner and wont use WS or Socket.io now. It's too much for me at this point.
Thanks in advance!
export default function useGetChatMessages(_id) {
const [chatMessages, setChatMessages] = React.useState([]);
React.useEffect(() => {
const interval = setInterval(() => {
getChatMessages(_id).then(fetchedChatMessages => {
setChatMessages(fetchedChatMessages);
});
}, 2000);
return () => clearInterval(interval);
}, [_id]);
return chatMessages;
}
This is my server function with express. I guess it should be implemented here rather than in my hook
router.get('/:id/messages', async (request, response) => {
try {
const chat = await Chat.findById(request.params.id);
response.json(chat.messages);
} catch (error) {
console.log(error);
response.status(500).json({ message: error.message });
}
});
Share
Improve this question
edited Jan 8, 2020 at 16:19
Sascha Rissling
asked Jan 8, 2020 at 15:12
Sascha RisslingSascha Rissling
3331 gold badge5 silver badges20 bronze badges
1
- 2 Personally, I think WS or Socket.IO is easier to implement than polling by magnitudes – yqlim Commented Jan 8, 2020 at 15:57
2 Answers
Reset to default 11Long polling is basically a way to keep an HTTP connection open, so you would need to implement this on the server side, your front end cannot control what the server does with the request.
As a side note, long polling is generally much more taxing on the server than websockets, and honestly your time would be better spent implementing a websocket connection, setting up a basic ws server is not that difficult if you use a library such as socket.io
Edit: Just as a semantic note, Long polling is an event driven way for the server to send back responses to the client without the client sending a specific request asking for that data, whereas regular polling is just sending requests at a specific interval (It sounds like you already know this because you mentioned wanting to make your polling more instant).
If you are interested in improving your regular polling setup take a look at the other answer.
Long polling requires changes in the backend as well. So assuming you cannot change the server-side code, you can still implement a more prehensive basic http polling.
To perform a basic http polling, you must call your API after the last successful call, so you make sure that only one API call is being queued.
I also added a rough Exponential Backoff to better handle errors. That will prevent your frontend hammering your server if you have backend issues (e.g. outage).
An adaptation of your code would look like this:
export default function useGetChatMessages(_id) {
const [chatMessages, setChatMessages] = React.useState([]);
React.useEffect(() => {
let delay = 1000;
let timeout = null;
const updateChat = () => {
getChatMessages(_id).then(fetchedChatMessages => {
// you must also consider passing a timestamp to the API call
// so you only fetch the latest messages, instead of all of them every time
// your state update would look like this:
// setChatMessages((messages) => [...messages, fetchedChatMessages]);
setChatMessages(fetchedChatMessages);
// reset the delay in case an error has happened and changed it.
delay = 1000;
// now call the API again after 1 second
timeout = setTimeout(updateChat, delay);
}).catch(error => {
// exponential backoff here.
// 1 - the first error will call the API after 2sec
// 2 - the second error will call the API after 4 sec
// 3 - the third error will call the API after 8 sec
// and so on
console.error("Could not update chat. waiting a bit...", error);
delay = delay * 2;
timeout = setTimeout(updateChat, delay);
});
}
return () => timeout && clearTimeout(timeout)
}, [_id]);
return chatMessages;
}