84669 Lernen von Personen
152542 Lernen von Personen
20005 Lernen von Personen
5487 Lernen von Personen
7821 Lernen von Personen
359900 Lernen von Personen
3350 Lernen von Personen
180660 Lernen von Personen
48569 Lernen von Personen
18603 Lernen von Personen
40936 Lernen von Personen
1549 Lernen von Personen
1183 Lernen von Personen
32909 Lernen von Personen
假如现在有三个选项卡,点击某个选项卡就通过ajax的方式加载出其中的内容,如果网速过慢导致内容没有加载出来,用户就点击其他的选项卡,如何保证加载出来的结果是正确的,和能否将请求延迟发送等?
这是个好问题。不知道题主是否熟悉自由测试和弱网测试这两个提法——这其实就是你提出的测试需求。
简而言之:
自由测试就是乱点;
弱网测试就是人为制造掉包和延迟(可能制造成随机或确定性的)。
这两个测试都是非常重要的。程序能否顶住这两项测试,保证一切情况下的响应都是合理的(而不是跑飞),这是开发者对健壮性把握如何的一个重要指标。
问题一分为二地看。先忽略“点击速率的控制”,仅看“如何保证加载结果正确”这一点。
从体验的角度来看,用户点击多个选项卡时,内容应该仅以用户点击的最后一个选项卡为准。毕竟用户点击了新的选项卡,就包含着“之前没加载出来的旧选项卡,全都丢弃不要了”的潜台词。
考虑这个序列:选项卡1点击 - 选项卡2点击 - 选项卡1响应到达 - 选项卡2响应永远丢包。此时用户体验来看,弹出选项卡1必然是怪异的(我明明点击的是选项卡2!)。
选项卡1点击 - 选项卡2点击 - 选项卡1响应到达 - 选项卡2响应永远丢包
唯一的正确答案是:显示为选项卡2永远加载中(或者提示超时出错,允许用户重新加载),而永远丢弃选项卡1的响应。
从这个意义上,AJAX请求的发出你是不应当阻止的。你的真正需求是:发出新的AJAX请求的时候,如何将旧的请求全部停下来。
这里必须说明的是:AJAX对象,保证HTTP的响应与请求一一对应。
具体而言: 某个具体的XMLHttpRequest实例发出了HTTP请求。 那么此HTTP请求的响应,就会回到发请求的那个XMLHttpRequest实例上。 这一点自动、必然、绝对、100%准确无误,并且由浏览器(或JS引擎)直接保证,无需任何编程干预。 以上是针对原生AJAX而言的。jQuery也一样,只是对象变成了jQuery封装过的jqXHR而已。 1次AJAX请求必然有1个实例,多个请求那就有多个实例来管理,这与任何其他条件无关,根本不用考虑“多个AJAX请求相同页面,响应会不会对应乱了”这种杞人忧天的问题。 你说回调?那只不过是挂载在各个AJAX对象实例上的一个普通成员变量(JavaScript里函数和变量同为一等公民)。请求对象对应正确了,回调自然也不会乱。
具体而言:
某个具体的XMLHttpRequest实例发出了HTTP请求。
XMLHttpRequest
那么此HTTP请求的响应,就会回到发请求的那个XMLHttpRequest实例上。
这一点自动、必然、绝对、100%准确无误,并且由浏览器(或JS引擎)直接保证,无需任何编程干预。
以上是针对原生AJAX而言的。jQuery也一样,只是对象变成了jQuery封装过的jqXHR而已。
jqXHR
1次AJAX请求必然有1个实例,多个请求那就有多个实例来管理,这与任何其他条件无关,根本不用考虑“多个AJAX请求相同页面,响应会不会对应乱了”这种杞人忧天的问题。
你说回调?那只不过是挂载在各个AJAX对象实例上的一个普通成员变量(JavaScript里函数和变量同为一等公民)。请求对象对应正确了,回调自然也不会乱。
这种1次请求对应1个对象的关系,就给了我们在AJAX请求发出后,仍然能对其进行控制的可能。
我们确实通常把 $.ajax() 当语句使用($.ajax(settings);),但事实上 $.ajax() 是有返回值的。$.ajax() 返回此次请求对应的 jqXHR 对象,我们可以通过此对象,来影响和操作这次请求本身。
$.ajax()
$.ajax(settings);
那么每次点击选项卡都发出请求,但只响应用户发出的最后一个请求的代码就非常好写了:
$(function() { $('#单选你的选项卡的容器').data('request_buffer', null); }); $('.多选你的每一个选项卡').click(function() { // 旧的HTTP请求直接放弃加载 var previous_jqxhr = $('#单选你的选项卡的容器').data('request_buffer'); if (previous_jqxhr) { previous_jqxhr.abort(); } var current_jqxhr = $.ajax({ type: your_type, url: your_url, data: your_data, timeout: your_timeout_seconds * 1000, context: this, }) .beforeSend(function() { // 显示点loading小动画什么的 }) .done(function() { // 点亮你点击的选项卡,灭掉其他的 $('.多选你的每一个选项卡').removeClass('.选项卡点亮的效果'); $(this).addClass('.选项卡点亮的效果'); // 填充正文区域 $('#单选你显示正文的区域').html(你得到的响应正文); }) .fail(function() { // 你认为合适的超时处理 }); // 新的请求顶掉旧的请求 $('#单选你的选项卡的容器').data('request_buffer', current_jqxhr); });
回调函数是控制HTTP请求的jqXHR对象调用的,所以如果不加污染,那么回调函数内的this指的是jqXHR本身。那么回调函数在调用到的时候,根本没有办法反查到你点击了哪个选项卡。
this
所以一定注意代码里那个context。jqXHR对象的context,确定了jqXHR在调用回调函数的时候,把回调函数内看到的this污染成谁。
context
只有在产生jqXHR的时候(即调用$.ajax()时)明确告知“此请求和哪些对象有联系”,在回调的时候才不会迷失方向,导致一些设置视觉效果的需求做不出来。
实现要基于事物的本源。如果一个AJAX请求要丢弃,那就应当把请求对象本身挖出来,通知他自己放弃。
这样不但彻底把待丢弃的无效回调本身消灭,更可以命令浏览器直接断开HTTP连接,节省宝贵的流量和并发数。这一点也是很重要的。
而明知道请求用不着了还要接收下来,再以“提前return”之类的修补手段“手工丢弃”,这个绕圈子的方案明显是不够优的。
实际上以上的措施,已经能够达到“保证加载结果正确”的目的了。 用户点得快,发出的请求多又怎么样? 反正同一时刻同时只有1条请求在网上跑,只有1个回调有调到的可能,一切的干扰要素都排除光了。
在此基础上,如果引入“限制用户点击的速率”,那么就是纯粹为了减轻服务器压力考虑了。
这个的办法就更加简单:用户点击一个选项卡(启动HTTP请求发送,可以挂在beforeSend事件上)时把所有的选项卡置灰。(不能点是必须明确提示用户的)
beforeSend
然后等待以下两个触发条件触发任意一个,就可以把所有的选项卡恢复点击:
成功分支:用户点的这个选项卡加载成功了(立刻允许用户切换到其他选项卡)
失败情况:用户点击之后过去了 X 秒(加载不出来了,允许用户发出新的请求)
这个的代码就略了。
两个方案:
ajax期间,其他tab全部disabled
设个变量loading,记录是否在请求,只有当loading为false时才发请求
1,首先需要确定的是用户需要连续发送两次请求 无论结果如何两次请求不干扰都需要有效,那我们是不应该阻止用户请求的。
2,如果第二次的请求需要第一次的请求结束后才能发起,那我们肯定是应该要阻止的。
3,至于楼主说的恶意点击,你是说不想服务器多次处理这样的请求么?那是服务器的事情了。
在进行与界面更新相关的AJAX操作时,应考虑在请求前对页面进行遮罩,请求完成后解除,以此来提升界面的响应性以及规避用户再次请求。
取消其他请求或者定时器控制请求都ok。不过我觉得也可以不用考虑取消。都加载回来然后缓存到本地,保证同一数据请求一次。当然也可以结合考虑
我只想说一点,ajax可以设置成同步请求,如果我做这个需求,我会在用户点击一个选项卡之后启动一个遮罩loading层,锁住UI,使用户无法点击其它的操作,然后超时、响应什么的你再具体处理
这是个好问题。不知道题主是否熟悉自由测试和弱网测试这两个提法——这其实就是你提出的测试需求。
简而言之:
自由测试就是乱点;
弱网测试就是人为制造掉包和延迟(可能制造成随机或确定性的)。
这两个测试都是非常重要的。程序能否顶住这两项测试,保证一切情况下的响应都是合理的(而不是跑飞),这是开发者对健壮性把握如何的一个重要指标。
问题一分为二地看。先忽略“点击速率的控制”,仅看“如何保证加载结果正确”这一点。
从体验的角度来看,用户点击多个选项卡时,内容应该仅以用户点击的最后一个选项卡为准。毕竟用户点击了新的选项卡,就包含着“之前没加载出来的旧选项卡,全都丢弃不要了”的潜台词。
考虑这个序列:
选项卡1点击 - 选项卡2点击 - 选项卡1响应到达 - 选项卡2响应永远丢包
。此时用户体验来看,弹出选项卡1必然是怪异的(我明明点击的是选项卡2!)。唯一的正确答案是:显示为选项卡2永远加载中(或者提示超时出错,允许用户重新加载),而永远丢弃选项卡1的响应。
从这个意义上,AJAX请求的发出你是不应当阻止的。你的真正需求是:发出新的AJAX请求的时候,如何将旧的请求全部停下来。
这里必须说明的是:AJAX对象,保证HTTP的响应与请求一一对应。
这种1次请求对应1个对象的关系,就给了我们在AJAX请求发出后,仍然能对其进行控制的可能。
我们确实通常把
$.ajax()
当语句使用($.ajax(settings);
),但事实上$.ajax()
是有返回值的。$.ajax()
返回此次请求对应的jqXHR
对象,我们可以通过此对象,来影响和操作这次请求本身。那么每次点击选项卡都发出请求,但只响应用户发出的最后一个请求的代码就非常好写了:
回调函数是控制HTTP请求的
jqXHR
对象调用的,所以如果不加污染,那么回调函数内的this
指的是jqXHR
本身。那么回调函数在调用到的时候,根本没有办法反查到你点击了哪个选项卡。所以一定注意代码里那个
context
。jqXHR
对象的context
,确定了jqXHR
在调用回调函数的时候,把回调函数内看到的this
污染成谁。只有在产生
jqXHR
的时候(即调用$.ajax()
时)明确告知“此请求和哪些对象有联系”,在回调的时候才不会迷失方向,导致一些设置视觉效果的需求做不出来。实现要基于事物的本源。如果一个AJAX请求要丢弃,那就应当把请求对象本身挖出来,通知他自己放弃。
这样不但彻底把待丢弃的无效回调本身消灭,更可以命令浏览器直接断开HTTP连接,节省宝贵的流量和并发数。这一点也是很重要的。
而明知道请求用不着了还要接收下来,再以“提前return”之类的修补手段“手工丢弃”,这个绕圈子的方案明显是不够优的。
实际上以上的措施,已经能够达到“保证加载结果正确”的目的了。
用户点得快,发出的请求多又怎么样?
反正同一时刻同时只有1条请求在网上跑,只有1个回调有调到的可能,一切的干扰要素都排除光了。
在此基础上,如果引入“限制用户点击的速率”,那么就是纯粹为了减轻服务器压力考虑了。
这个的办法就更加简单:用户点击一个选项卡(启动HTTP请求发送,可以挂在
beforeSend
事件上)时把所有的选项卡置灰。(不能点是必须明确提示用户的)然后等待以下两个触发条件触发任意一个,就可以把所有的选项卡恢复点击:
成功分支:用户点的这个选项卡加载成功了(立刻允许用户切换到其他选项卡)
失败情况:用户点击之后过去了 X 秒(加载不出来了,允许用户发出新的请求)
这个的代码就略了。
两个方案:
ajax期间,其他tab全部disabled
设个变量loading,记录是否在请求,只有当loading为false时才发请求
1,首先需要确定的是用户需要连续发送两次请求 无论结果如何两次请求不干扰都需要有效,那我们是不应该阻止用户请求的。
2,如果第二次的请求需要第一次的请求结束后才能发起,那我们肯定是应该要阻止的。
3,至于楼主说的恶意点击,你是说不想服务器多次处理这样的请求么?那是服务器的事情了。
在进行与界面更新相关的AJAX操作时,应考虑在请求前对页面进行遮罩,请求完成后解除,以此来提升界面的响应性以及规避用户再次请求。
取消其他请求或者定时器控制请求都ok。
不过我觉得也可以不用考虑取消。
都加载回来然后缓存到本地,保证同一数据请求一次。
当然也可以结合考虑
我只想说一点,ajax可以设置成同步请求,如果我做这个需求,我会在用户点击一个选项卡之后启动一个遮罩loading层,锁住UI,使用户无法点击其它的操作,然后超时、响应什么的你再具体处理