本周继续Canvas的学习,话说过几天就是新年了,放着几天假,也没人约,估计宅家里了,那就搞搞技术,学学东西。本周学习相关JS动画。
说起时间的循环,莫过会提到SetTimeOut 以及 SetInterval。这两个函数初学JS的人都不会陌生。因为相关动画的实现需要他们对时间的控制,也就是动画的帧频。利用一张一张图片的快速播放,实现的动画效果,时间函数的控制尤为重要,他决定动画的流畅效果。
SetTimeOut
这里我们不谈SetTimeOut 的实现方式,谈谈SetTimeOut如何工作的。
我们知道,js是单线程执行的,基于时间队列,想起了大学操作系统相关的进程的时间管理,有需要的同学可以自行补课OS。所以其实setTimeout和setInterval所谓的“异步调用”事实上是通过将代码段插入到代码的执行队列中实现的。 而如何计算插入的时间点呢?自然是要用到我们所说的timer,也就是计时器。当执行setTimeout和setInterval的时候,timer会根据你设定的时间“准确”地找到代码的插入点。当队列“正常”地执行到插入点时,就触发回调,也就是我们设定的回调函数。
分析下面代码:
function a() {
setTimeout(function(){alert('can you see me?');},1000);
while(true) {}
}
问是否会执行 alert?
答案是不行的。为什么呢?
基于上面的原理我们得出答案:
因为,while这段代码没有执行完(浏览器一直在解析while的代码),所以插入在后面的代码便永远不会执行。 其实JS终归是单线程产物。无论如何“异步”都不可能突破单线程这个障碍。所以许多的“异步调用”(包括Ajax)事实上也只是“伪异步”而已。
这就是这周一个同事问我问题的答案。他遇到的问题就是程序在循环遍历中无法进行交互。
那么解决办法就是程序利用闭包进行循环的异步操作。将循环的每一步插入到可用的时间分片里。
有个函数库Concurrent.Thread.js 就是实现js的多线程的。使用方法:
Concurrent.Thread.create(function(){
for (var i = 0;i<1000000;i++) {
console.log(i);
};
});
在此期间浏览器不会出现卡死。交互OK。
具体下载地址:
Concurrent.Thread.js
或者使用 web Worker 实现。
参考文档:
web Worker
setTimeout
Worker wiki