众所周知JavaScript这门语言是单线程,可是为何要设计成单线程呢?明明多线程更加有效率。前端
这里咱们就要从JavaScript的用途来考虑,JavaScript是一门浏览器脚本语言,也就是说它须要操做DOM来更改页面展现,提供用户良好的上网体验。这时候单线程的好处就体现出来,不妨想象一下:promise
若是JavaScript是多线程的语言,当一个线程正在进行一个DOM的删除操做,这是另外一个线程出来搞事情,进行这个DOM的修改操做。这种状况要怎么处理呢?这样的场景就会出现一些问题。浏览器
因此说JavaScript单线程的设计是从它的用途出发的,而且在之后也会一直坚持单线程的设计。bash
单线程就像是你们在食堂排队打饭,若是想打到饭,那就必须等食堂大妈一个一个把排在前面的人的饭打完才能轮到你。可是,若是JavaScript真的是这样那就糟糕了。不妨想一下,若是我访问的这个网站有一个超清图片,加载很慢,难道是要用户等到图片彻底加载出来以后才能进行其余的操做嘛,显然如今咱们浏览网站并不会出现这样的状况,那这又是怎么一回事呢?多线程
那是由于JavaScript的任务分为同步任务和异步任务两种:异步
同步任务就是进入主线程的任务,必须排队一个一个按顺序的执行。函数
开发者们认识到,像费时的IO操做,接口请求彻底能够不理他们,将他们暂时挂起,放入事件表(Event Table)中当,主线程中的任务执行完,再来“宠幸”它们。这种暂时挂起的任务就是异步任务。oop
每个异步任务都须要指定一个事件,例如当耗时的IO操做执行完以后,就会将它指定的这个事件添加到任务队列中,这个事件就是回调函数。学习
因此说咱们常常说的主线程开始执行异步任务了,其实主线程执行的是异步任务的回调函数。网站
如今来分析一下上图中的事件执行顺序:
上述的过程会不断的重复执行,这个重复的过程就是咱们一般所说的事件循环机制(Event Loop),看下面代码:
console.log(1);
document.body.onclick = function () { console.log('2'); }
console.log(3);复制代码
JavaScript中的给DOM注册一个点击事件,这个点击事件其实就是一种异步任务,由于咱们不知道用户何时才会点击。
如今咱们根据上图来分析一下这段代码的执行:
1.首先主线程会将同步的console.log操做放在主线程中执行,
2.首先打印出1,3
3.同时将点击事件放入到事件表中,当用户点击body后,JS会在事件队列中注册点击的回调函数。
4.这时主线程任务执行完毕,去任务队列中检查是否有须要执行的任务,这是发现了点击body的回调函数,JavaScript就会将这个回调函数放在主线程中执行。
5.全部就打印出了1,3,2的结果。
异步任务其实还能够细分为宏任务和微任务,他们的区别就是执行顺序的不一样,下面咱们就讨论一下他们具体的执行顺序,在Event Loop中到底有什么不一样。
其实异步任务的执行是有两个执行队列的,一个是宏任务队列,一个是微任务队列,每次执行的时候,首先是去微任务队列中查看是否有须要执行的任务,而后再去宏任务执行队列中查看是否有须要执行的事件。
宏任务:总体的script代码,setTimeout,setInterval、setImmediate
微任务:promise,process.nextTick
咱们如今根据这个流程图来分析一下具体的执行顺序:
如今咱们来分析一段代码,看看输出的顺序是否符合上面的流程图:
因此上述代码最终的输出应该是:1,6,7,2,4,9,10,5,11,8,3
但愿你们看完这篇文章可以有收获,哪里写的不对也但愿各位大佬多加指点,本文章仅为记录前端小白的学习过程,谢谢你们!