单线程
单线程是JavaScript语言的一大特色。
单线程,也就是同一时间只能做一件事情。
但是为什么是单线程呢?
因为作为浏览器脚本语言,JavaScript的主要用途是与用户互动,以及操作DOM。如果JS是多线程的话,两个线程同时对DOM进行操作,会出现冲突,所以为了避免冲突、提高效率,JS为单线程语言。
H5添加了webworkers多线程,是不是打破了JS是单线程的本质?
为了利用多核CPU的计算能力,H5提出Web Worker标准,允许JS脚本创建多个线程,但是子线程完全受主线程控制,且不得操作DOM。所以,这个新标准并没有改变JavaScript单线程的本质。
任务队列
同步任务队列(Synchronous)
在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务队列(Asynchronous)
不进入主线程,而是进入异步任务队列(Asynchronous Task Queue),只有当同步任务执行完毕,且轮到异步任务才会进入主
线程执行。
事件轮询(Event Loop)
(1)所有同步任务都在主线程上执行,形成一个执行栈(execution context stack)。
(2)执行栈上的同步任务执行完毕后。只要异步任务有了运行结果,就在异步任务队列中放置一个事件。
(3)一旦"执行栈"中的所有同步任务执行完毕,系统就会读取异步任务队列,看看里面有哪些事件。
那些对应的异步任务,于是结束等待状态,进入执行栈,开始执行。
(4)主线程不断重复上面的第三步。
实例演示
demo代码如下:
console.log(1);//同步任务
setTimeout(function() {
console.log(2);//异步任务
}, 100);
setTimeout(function() {
console.log(3);//异步任务
});
console.log(4);//同步任务
执行结果:大家也知道,是1、4、3、2
同步队列 | 异步队列 |
console.log(1); | function() {console.log(3);} |
console.log(4); | function() {console.log(2);} 100m后放入 |
1. 首先把任务分类,console.log(1);放入同步任务队列;
2. 然后两个setTimeout一个等待100ms、一个是立即执行,所以function() {console.log(3);}会先于function() {console.log(2);}
放入异步队列中,而function() {console.log(2);}会在100ms后放入异步队列中;
3. 最后console.log(4);放在放入同步任务队列;
4. 当同步任务执行完毕后,浏览器引擎回到异步队列中看里面有没有待执行的函数,如果有,则立即执行;没有,则一直
监听着。由于计算机执行速度是毫秒级的,所以100ms对它来说事件很长,当它执行完第一个异步任务时,第二个异步任务还
没进来。要等到100ms结束后,第二个任务进来,才能马上执行。再次期间,引擎一直在进行着轮询的工作。