从setTimeout说起
这是一个JS引擎当中内置的定时器函数官方的定义如下setTimeout() 方法用于在指定的毫秒数后调用函数或计算表达式
但是实践证明 , 即使是setTimeout(fn, 0)
fn函数也不会立即被执行例如下列代码console.log(1);var timeFunc = function(){ console.log(2);}setTimeout(timeFunc,0);console.log(3);
执行的结果是1 3 2 , 而不是1 2 3
JS引擎的单线程特性
JS语言设计的一个很重要的特点就是 : JS是没有多线程的
但是JS引擎是单线程 , 浏览器却可以是多线程 , JS引擎只是浏览器的一个线程而已定时器 网络请求 浏览器渲染等操作 , 都是由不同的线程去完成的比如下面这个例子var isEnd = true;window.setTimeout(function () { isEnd = false; }, 1000);while (isEnd);console.log('end');
在1s之后 , 将isEnd置为false , 表面看来后面的死循环只会持续1s而已
但是实际上这段代码会一直陷入死循环这也证明了setTimeout并不能实现多线程JS是基于事件驱动的语言 , 它的执行顺序遵循事件队列的机制
浏览器有各种各样的线程 , 这些线程的联系都是基于事件的 , 当JS引擎处理到与其他线程相关的代码 , 就会分发到其他的线程
在这个过程中 , JS引擎并不会阻塞自己的线程等待其他线程执行完毕 , 而且其他线程执行完毕后添加事件任务告诉js引擎执行相关操作 , 这就是js的异步编程模型
. 拿上面的定时器函数来说 , 执行这个函数的时候 , 就会开启一个定时器线程( 注意: 这个线程并不属于JS引擎 ) , 这个线程会在指定时间后向事件队列中添加一个任务 , 这个任务就是执行传递给setTimeout的函数
既然是队列 , 后入队的任务当然会在主线程的任务之后执行如果主线程的任务一直不结束 , 那么这个队列就会一直阻塞
这同样也可以解释同步ajax请求 , 当后台响应较慢的时候造成的页面假死现象页面要与用户进行交互 , 依靠的是响应事件 , 比如鼠标点击事件等但是主线程任务一直不结束 , 点击事件的任务只能在后面排队 , 事件方法不会被执行 , 当然就有了假死现象当主线程任务结束的时候 , 这些事件方法仍然会执行
由此可见官方对于settimeout的定义是有迷惑性的.应该给一个新的定义:
在指定时间内, 将任务放入事件队列,等待js引擎空闲后被执行.