将基本轮询变为长轮询
Turn basic polling into long polling
我正在开发一个聊天应用程序,到目前为止,我每两秒轮询一次我的服务器以获取消息。为了使聊天更加即时,我想实施长轮询。我正在尝试为此实现此 JS.info Guide,但我一直没有达到我打算达到的目标。谁能为我指出这一点?
我在 React 中有一个自定义挂钩,目前是基本轮询。
仅供参考:我是初学者,现在不会使用 WS 或 Socket.io。在这一点上对我来说太多了。
提前致谢!
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;
}
这是我的 express 服务器功能。我想它应该在这里实现而不是在我的钩子中实现
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 });
}
});
长轮询基本上是一种保持 HTTP 连接打开的方法,因此您需要在服务器端实现它,您的前端无法控制服务器对请求执行的操作。
作为旁注,长轮询通常比 websockets 对服务器的负担要大得多,老实说,你的时间最好花在实现 websocket 连接上,如果你使用socket.io
等库
编辑:正如语义说明,长轮询是一种事件驱动的方式,服务器无需客户端发送特定请求即可向客户端发送响应,而常规轮询只是发送请求一个特定的时间间隔(听起来你已经知道了,因为你提到想让你的轮询更即时)。
如果您有兴趣改进常规轮询设置,请查看其他答案。
长轮询也需要更改后端。所以假设你不能更改服务器端代码,你仍然可以实现更全面的基本http轮询。
要执行基本的 http 轮询,您必须在最后一次成功调用后调用您的 API,因此您要确保只有一个 API 调用正在排队。
我还添加了一个粗略的 Exponential Backoff 以更好地处理错误。如果您有后端问题(例如中断),这将防止您的前端攻击您的服务器。
您的代码改编如下:
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;
}
我正在开发一个聊天应用程序,到目前为止,我每两秒轮询一次我的服务器以获取消息。为了使聊天更加即时,我想实施长轮询。我正在尝试为此实现此 JS.info Guide,但我一直没有达到我打算达到的目标。谁能为我指出这一点?
我在 React 中有一个自定义挂钩,目前是基本轮询。
仅供参考:我是初学者,现在不会使用 WS 或 Socket.io。在这一点上对我来说太多了。
提前致谢!
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;
}
这是我的 express 服务器功能。我想它应该在这里实现而不是在我的钩子中实现
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 });
}
});
长轮询基本上是一种保持 HTTP 连接打开的方法,因此您需要在服务器端实现它,您的前端无法控制服务器对请求执行的操作。
作为旁注,长轮询通常比 websockets 对服务器的负担要大得多,老实说,你的时间最好花在实现 websocket 连接上,如果你使用socket.io
等库编辑:正如语义说明,长轮询是一种事件驱动的方式,服务器无需客户端发送特定请求即可向客户端发送响应,而常规轮询只是发送请求一个特定的时间间隔(听起来你已经知道了,因为你提到想让你的轮询更即时)。
如果您有兴趣改进常规轮询设置,请查看其他答案。
长轮询也需要更改后端。所以假设你不能更改服务器端代码,你仍然可以实现更全面的基本http轮询。
要执行基本的 http 轮询,您必须在最后一次成功调用后调用您的 API,因此您要确保只有一个 API 调用正在排队。
我还添加了一个粗略的 Exponential Backoff 以更好地处理错误。如果您有后端问题(例如中断),这将防止您的前端攻击您的服务器。
您的代码改编如下:
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;
}