JS 如何实现无限次数的顺序请求?

2017-08-28 10:41:38 +08:00
 abcbuzhiming
有个功能叫长轮询,很多时候用于要求不特别高的 web 消息推送或者 webim 聊天。基本原理是客户端向服务器发起一次请求后,该请求就被服务器 hold 住 n 秒(从 30-90s 不等),此时如果服务器发现有属于这个连接的新消息,就返回消息,然后本次请求结束,客户端再次发起下一次请求,无限循环。

这里面有两个难点:
请求是顺序的,一个请求结束后才发起另外一个,也就是说是链式请求,而大部分的客户端异步请求是不会等待一个完结才开始另外一个的。
请求的数目是无限的,不是有限的。类似 Porimse 这样的链式请求的实现从方式上看其实是先把有限个请求任务全部串起来,然后再让它们执行。而我这里,请求数目理论上是无限的,所以不能预先串好

有个叫 sockjs 的库在低版本 IE 上就能实现这样“无限链式请求”功能,我看了很久代码,还是没搞懂原理,请指点
4102 次点击
所在节点    JavaScript
29 条回复
alber1986
2017-08-28 10:44:13 +08:00
我也想知道
biuuu
2017-08-28 10:52:15 +08:00
用递归啊
Arrowing
2017-08-28 10:56:05 +08:00
在客户端的 ajax 代码里,success 和 error 里发出下一次请求,难道这样不可以吗?
chenyu8674
2017-08-28 10:59:37 +08:00
没太理解 LZ 的意思,不过从描述来看不难实现啊
1. 从前一个请求的 onResponse 里触发下一个请求
2. 维护一个请求任务列表按顺序调用
abcbuzhiming
2017-08-28 10:59:54 +08:00
@biuuu 逻辑设计上讲,用递归是不合理的,递归从原理上讲必须有出口,也就是递归深度是事先设定好的,有穷的,虽然我这个案例里 JS 的请求从实际上讲,必然会有退出的可能性(比如出错),但是从场景上来讲,这是一个无限循环,所以我觉得递归没法用在这里,难道你不怕栈溢出?还是你说的递归和我想的不是一个东西?
ETiV
2017-08-28 11:01:45 +08:00
async.queue

并发设置好,直接 push 相应数量的回调函数;每一次请求收到响应后再 push 一次,就可以车轮一样,无限次了……

另外你要是做聊天,不要「一个请求结束后才发起另外一个」,相邻两次连接中间的空档期会丢消息的。
wunonglin
2017-08-28 11:02:17 +08:00
怎么不用 WebSocket ?
abcbuzhiming
2017-08-28 11:12:09 +08:00
@chenyu8674
1 方法这算回调吧
2.方法是啥意思,能说明白点不
abcbuzhiming
2017-08-28 11:13:08 +08:00
@ETiV 你这是客户端的东西?我放狗半天没搜到,我现在要解决的是客户端无限轮询问题,服务端不需要担心,不会丢消息的
abcbuzhiming
2017-08-28 11:13:21 +08:00
@wunonglin IE8,没法用
hxsf
2017-08-28 11:15:31 +08:00
function fetch_once () {
fetch(......, function(err, data) {
// your codes here
setTimeout(fetch_once, 1000 /* delay */ ) // or use `nextTick`
})
}
ETiV
2017-08-28 11:17:54 +08:00
@abcbuzhiming
搜这个 site:npmjs.com async
里面有个.queue 方法
flowfire
2017-08-28 11:18:54 +08:00
let getMessage = cb => {
// xhr 操作
xhr.onreadyStateChange = () => {
// if(XXX) return;
let res = xhr.responseText;
if (res.success) {
// 操作数据
}
cb();
}
}

........我还是没懂难度在哪里
flowfire
2017-08-28 11:21:54 +08:00
如果可以用 async 那就更简单了
let do = async () => {

while(true){
await new Promise((res,rej)=>{
// xhr 操作
// 收到数据后 res();
});
}

}

do();
flowfire
2017-08-28 11:24:34 +08:00
@flowfire #14 我忘记 do 是关键字了。。。。
flowfire
2017-08-28 11:28:44 +08:00
abcbuzhiming
2017-08-28 11:30:09 +08:00
谢谢各位,我想我明白咋回事了,因为最近写 Promise,我的思路走死胡同了,老是在想串链任务,其实就像
@chenyu8674 @flowfire 说的,回调里调用自身就能解决
iskyzh
2017-08-28 11:34:45 +08:00
@abcbuzhiming 个人认为 JavaScript 里的回调不能等同于递归。诸如 function a() { a(); } 必然是会栈溢出的。但是回调不应该这么理解,因为触发事件执行回调的时候,入口函数应该是「被触发的事件」,而非「注册回调的地方」。因此在 onsuccess/onerror 里再去发 ajax 请求是可行的,而且不会导致爆栈。
t123yh
2017-08-28 14:12:05 +08:00
给楼主指条明路:socket.io 向下支持到 IE6
mooncakejs
2017-08-28 14:19:33 +08:00
const loop = async ()=>{
while(true){
await ping()
await sleep(10000)
}
}

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/386282

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX