setTimeOut引发的异步函数思考

今天在博客上看到了一篇setTimeOut异步函数的文章,正好自己也不是很清楚,看完后感觉启发很大。

JavaScript运行环境

JS是单线程的,意思就是 同一时刻只能做一件事情。
但是要如何同时响应不同的操作呢?
先以BOSS来称呼JS的主线程,Boss为了更多更快地处理用户的需求,会不停地接收任务来执行。为了进一步提交效率,他 优先执行最紧急的任务(即刻要执行),如果你要和他说”等下(3秒后 / 如果有我点了按钮 / 如果收到了服务器的响应)帮我在控制台打一个log吧。”,BOSS不会专门等着去执行你的需求,而是默默地把你这个”伪需求”记在一个”小本本”上,然后拍拍胸脯和你说:”我保证(I promise!)”,接着继续做手头上的事,等BOSS手头上事情做完了,会从小本本上选择 最早记录的没被执行的任务来执行。

BOSS能力和时间有限,能做的只有这么多了。他Promise会帮你做的任务肯定会做(只要他没有猝死。。),但时间上可能并不一定严格符合你的要求,毕竟小本本上可能不仅只有一条任务。

理解setTimeOut

上面的小故事中的称呼分别为:

JS主线程 => BOSS
同步任务 => BOSS手头上正在做的任务
异步任务(队列) => BOSS的小本本上的任务

我以前只知道setTimeout的意思让JS从现在开始,经过指定的时间后,执行相应的函数。

从方法名和大部分现象来看,很容易产生以上的误解。在我们理解了JS主线程的特点后,知道了它会优先完成同步任务,在同步任务执行过程中,不会执行其它任务。

实际上,setTimeout做的事情是:在指定delay时间后,将指定方法作为异步任务添加到异步任务队列中。

所以,如果setTimeout的定时到了执行时间,JS主线程仍然还在执行同步任务,setTimeout所指定的方法并不会立刻执行。

而且即使JS主线程执行完了同步任务,也不一定会执行setTimeout指定的方法,因为异步任务队列中可能有更早加入的异步任务。

除了setTimeout还有一个setInterval,setInterval可以通过设置的时间向主线程添加异步任务,但最重要的是:setInterval会检测待执行队列中的异步任务,防止重复添加,但是并不会检测正在执行的异步任务。

防止重复定时:

setTimeout(function() {
    doWhatYouWantTo();
    setTimeout(arguments.callee, 100)
}, 100);
本文总阅读量