在Web应用程序中,某个任务需要多个连续的ajax调用步骤才能完成。每个需要12-18秒。
我希望向用户提供一个进度指示器,而这个指示器经常会做出很少的步骤。
我的第一个赌注是假设一个线性progress = k * time
函数,在每个新响应上自我调整k
。 Fiddle emulated响应时间为+ - 4s范围内的随机值。
这种做法似乎是错误的:在一系列快速反应之后反应相对较长的情况下,进展会采取消极措施来赶上真正的步伐。
感觉就像一个函数应该进入“波浪”:开始时更快,在延迟检查点的情况下减慢到接近结束的程度。
完成此类任务的最佳做法是什么?
答案 0 :(得分:1)
我将专注于您的请求的数学部分:
一个函数应该进入“波浪”:开始时速度更快,在延迟检查点的情况下减慢到接近结束的程度
翻译:具有正初始梯度的单调函数(即没有后向步骤)和大x的渐近行为。
考虑atan(theta):对于小x,它的梯度为1,对于大x,渐近接近π/ 2。我们可以对它进行缩放,以便当块在可用长度的某个部分时发生预期的结束 - 也就是说,如果你期望它需要4秒,并且它需要4秒,它可以跳过剩余部分。如果需要更长的时间,剩下的就是我们将渐渐吃掉的东西。因此:
function chunkProgressFraction(expectedEndT, currentT, expectationFraction) {
// validate
if(!expectedEndT) { return 0; }
// defaults
if(!expectationFraction) { expectationFraction = 0.85 }
// y = k atan(mx)
// to reach 1.0 at large x:
// 1.0 = k . atan(+lots) = k . pi/2
var k = 2.0 / Math.PI;
// scale the function so that the expectationFraction result happens
// at expectedEndT, i.e.
// expectationFraction = k * atan(expectedEndT * m)
// expectedEndT * m = tan(expectationFraction / k)
var m = Math.tan(expectationFraction / k) / expectedEndT;
return k * Math.atan(m * currentT);
}
所以,如果我们想要达到100像素,我们希望它需要4个像素,我们希望20%松弛:
progressPixelsThisChunk = 100.0 *
chunkProgressValue(4000.0, thisChunkTimeInMilliseconds, 0.8);
一定要使用前一个块所花费的时间来扩展expectedEndT。