我想创建一个自定义进度条。但是我使用递归函数为其更新数据,我无法更新进度条中的画布。
以下是我的代码的一部分:
var length = 0;
recursiveFunction = function(){
length++;
updateLength(length);
//some work
recursiveFunction();
}
updateLength = function(length){
setLength(length);
}
setLength(length){
var c = document.getElementById(canvas);
var ctx = c.getContext("2d");
ctx.fillStyle = "#fc0";
ctx.fillRect(0, 0, length, 10);
}
所有这些函数都在不同的JS文件和不同的类中。
问题是画布没有在setLength
函数中重绘。
答案 0 :(得分:2)
这与JavaScript是单线程有关,当时只能做一件事。只要该代码正在运行,其他所有内容(例如更新到屏幕)都必须等待。
为了解决这个问题,您可以在代码中引入一些异步性,暂停代码,以便更新屏幕。
例如(注意:如果不执行其他更改,此更改本身可能无效):
recursiveFunction = function(){
length++;
updateLength(length);
//some work
requestAnimationFrame(recursiveFunction); // makes call async
}
该函数现在将结束,但会添加一个事件以供将来使用(在这种情况下通常为16.7ms)。同时画布可以更新为屏幕。
但当然不是没有问题。上下文正在改变,因为它是一个递归函数,你可能想传入参数。虽然帖子中没有显示哪些内容(如果有的话),但您可以使用requestAnimationFrame()
代替setTimeout()
来传递参数。如果您依赖上下文(例如bind()
),也可以使用this
。
// example of bind
requestAnimationFrame(recursiveFunction.bind(this));
setTimeout()
can take more arguments比延迟:
setTimeout(recursiveFunction.bind(this), 17, arg1, arg2, arg3, ...);
另一种方法是使用 Web Workers 。这将允许您在单独的线程上尽可能快地运行代码,并偶尔向主机发送一条消息,其中包含到目前为止的进度,这将允许独立更新画布。如果函数长时间运行,这是推荐的路径。 Web worker有good support但不适用于旧的IE或Opera Mini。