JS 多次请求 如何使后者覆盖前者

2022-08-18 16:33:10 +08:00
 yxcoder

多个 AJAX 请求,分别为 N1,N2,N3,N4,N5

N1 请求完成之后输出 console.log(1) N2 请求完成之后输出 console.log(2) 依此类推

如果 N1,N2,N3,N4,N5 依次执行,但是返回时间不确定,如何使最终输出的只有 5

这里的请求数量可能会很多,五个只是举例。 前者的请求无法取消

3547 次点击
所在节点    程序员
43 条回复
mxT52CRuqR6o5
2022-08-18 16:35:53 +08:00
简单一点的,保存上一个的 abortController ,下一次请求发出去前把上一个请求 abort 掉
复杂一点的,rxjs
westoy
2022-08-18 16:36:18 +08:00
一般数据都会记录一个 updated_at 的

返回的时候和之前那次比较, 取新的
Kenmin
2022-08-18 16:36:37 +08:00
善用 async await
doommm
2022-08-18 16:38:47 +08:00
我选 rxjs
ifbluethen
2022-08-18 16:39:35 +08:00
for(var c = 0; c < 5; c++) {
setTimeout(function() {
console.log(c);
}, 1000);
}
kop1989smurf
2022-08-18 16:39:41 +08:00
不懂这个“依次执行”的意思到底是什么。

1 、如果顺序固定,那么前面请求的意义是什么?
2 、如果顺序不固定,那么到底哪个请求才是“N5”?是花费时间最长的那个么?
zhanghx1991
2022-08-18 16:42:37 +08:00
我也选 rxjs
shyling
2022-08-18 16:43:55 +08:00
没看懂需求。。。

Promise.all 满足不了你?

知道要 5 不能只在 5log ?
ITsWHY
2022-08-18 16:44:15 +08:00
每个请求设置一个 id 再用一个全局的变量记录最后一个发的 id, if(全局 id != 当前请求 id) 就直接 return
yxcoder
2022-08-18 16:44:28 +08:00
@kop1989smurf 顺序执行,没有意义,用户的操作有啥意义可言呢,重要的是解决办法
ytll21
2022-08-18 16:44:54 +08:00
每个请求给一个编号,返回的值压入一个 array 中,按照编号排序,取最大编号的值。

或者再简单点,只保留一个值,只有当编号大于保留的值的编号时,才做更换。
Terry05
2022-08-18 16:45:10 +08:00
感觉你这种类似在短时间里一直轮询的场景,这种情况下如果下一个时间周期,上一个周期的请求还没完成,可以强制 cancel 各种 http request 库都有类似功能
woodensail
2022-08-18 16:46:08 +08:00
并发控制有几种不同的处理,可以根据不同需求选用。
1:发起新请求时如果有进行中的请求,则直接将老请求的 promise 丢回去。这种方式适用于不需要考虑时效性的请求接口。
2:乐观锁,每次进入长逻辑时将乐观锁+1 然后记录当前的值,逻辑执行中每个异步任务完成后都检查一次乐观锁是否变动,如果没变则可以继续执行,如果变了,则终止当前人物。这个方式适用于包含多个异步人物的长逻辑链条,且允许新操作覆盖旧操作的场景
3:简单的互斥锁,有进行中的请求则将新的操作废弃或者排队。一般提交类操作这么搞,前一个请求完成前,不允许发起第二个请求
这几个是我常用的手段,还有其他手段可以参考其他人的回复,比如上面说到的 abort 老的请求。
jamosLi
2022-08-18 16:49:22 +08:00
建议说场景 不说场景那就干掉异步
yxcoder
2022-08-18 16:50:21 +08:00
@mxT52CRuqR6o5 请求没法拦截掉,该走的逻辑还是会走,现在的问题是如何让它知道它后面又有个请求发出去了
@westoy 好像是可以,用时间戳做标志位,似乎可以解决,我试一下
@shyling 这里的 5 只是一个例子,可能有很多个,而且这些请求并不是预先就知道的,可能是前一个请求发到一半,来了另一个请求
@ITsWHY 没法为每一个请求记录一个 ID ,因为请求的数量其实是不固定的
kop1989smurf
2022-08-18 16:54:17 +08:00
@yxcoder #10
1 、请求触发回调时验证是否有新的请求,如果有则放弃执行回调逻辑。
2 、执行新请求之前,调用老请求 xhr 的.abort()方法。(各种库封装的不一样,需要针对库来使用)
yxcoder
2022-08-18 16:57:10 +08:00
@woodensail 第二种方法应该是 ok 的,和前面一个说时间戳的其实是一个道理
yxcoder
2022-08-18 17:01:09 +08:00
@kop1989smurf 你可以看下 2 楼和 13 楼的方案,你说的 1 对应的是互斥锁,2 方法在提问中就已经说明了前者的请求无法取消。可以使用乐观锁或者时间戳解决
keepeye
2022-08-18 17:01:16 +08:00
一个计数器就可以搞定的

let c = 0
function req() {
let n = c++
// .... 请求过程
if (n == c) {
console.log("....")
}
}
yxcoder
2022-08-18 17:05:42 +08:00
@keepeye 是的,其实就是维护一个无限增长的数

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

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

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

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

© 2021 V2EX