知乎看到的一个题

某个应用模块由文本框 input,以及按钮 A,按钮 B 组成。点击按钮 A,会向地址 urlA 发出一个 ajax 请求,并将返回的字符串填充到 input 中(覆盖 input 中原有的数据),点击按钮 B,会向地址 urlB 发出一个 ajax 请求,并将返回的字符串填充到 input 中(覆盖 input 中原有的数据)。

当用户依次点击按钮 A、B 的时候,预期的效果是 input 依次被 urlA、urlB 返回的数据填充,但是由于到 urlA 的请求返回比较慢,导致 urlB 返回的数据被 urlA 返回的数据覆盖了,与用户预期的顺序不一致。

请问如何设计代码,解决这个问题?

阅读 4.1k
7 个回答

ajaxA和ajaxB用同一个回调函数。

var response = {}
function callback(data,id) {
  response[id]=data
  if(response.a) {
    inputA.value =response.a
  } 
  if(response.a && response.b) {
    inputB.value=response.b
  } 
}

如果b比a先回来,input的内容不会变,A再回来的时候会两个依次显示,当然,在显示B的时候建议加一个延迟,不然A的立马被覆盖了
如果a比b先回来,input先显示A再显示B

唯一的解决方案,预取数据。在第一次请求完成前,已预取所有请求响应数据。那么当后续请求发送时,直接使用预取数据即可。此解决方案仅适合此题,并不一定适用于大多数实际场景。

其他的方案,如请求时阻止其他请求,或者增加请求队列等,都改变了此题原有题意,但却是实际场景中常见的解决方案。

这个很简单嘛,发一次请求的时候取消响应前面的请求。

首先UX觀點看我覺得反覆覆蓋用戶輸入不好...

如果這個方向成立, 可以寫一個鎖讓兩個流程互斥, A未結束時不開始B

首先全局保存一个版本Id和一个自增Id。
每一个请求发出前,自增Id更新,并保存一个副本在请求的scope中。请求结束后在输出到input之前,验证当前的scope里保存的Id是否大于等于全局版本Id,如果是,则更新input,并更新全局版本Id为当前请求的Id,反之则说明该请求之后又有新的请求发出,且已成功返回并更新input,需要丢弃这个请求结果。

  1. 从交互上解决,按了A时禁用B
  2. 代码层面上解决,粗暴点用个变量,请求了A且得到数据了加一,请求了B且得到数据减一,变量大于等于1时不请求A

应该是写入顺序要与请求开始顺序一致吧;
用一个队列就可以了, 后面加入的比重更高

渲染的时候从数组倒数去第一个有值的就可以了

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题