你们都知道js是单线程的脚本语言,在同一时间,只能作同一件事,为了协调事件、用户交互、脚本、UI渲染和网络处理等行为,防止主线程阻塞,Event Loop方案应运而生...html
我的博客了解一下:obkoro1.com面试
js做为主要运行在浏览器的脚本语言,js主要用途之一是操做DOM。ajax
在js高程中举过一个栗子,若是js同时有两个线程,同时对同一个dom进行操做,这时浏览器应该听哪一个线程的,如何判断优先级?浏览器
为了不这种问题,js必须是一门单线程语言,而且在将来这个特色也不会改变。网络
由于js是单线程语言,当遇到异步任务(如ajax操做等)时,不可能一直等待异步完成,再继续往下执行,在这期间浏览器是空闲状态,显而易见这会致使巨大的资源浪费。dom
当执行某个函数、用户点击一次鼠标,Ajax完成,一个图片加载完成等事件发生时,只要指定过回调函数,这些事件发生时就会进入任务队列中,等待主线程读取,遵循先进先出原则。异步
执行任务队列中的某个任务,这个被执行的任务就称为执行栈。函数
要明确的一点是,主线程跟执行栈是不一样概念,主线程规定如今执行执行栈中的哪一个事件。oop
主线程循环:即主线程会不停的从执行栈中读取事件,会执行完全部栈中的同步代码。post
当遇到一个异步事件后,并不会一直等待异步事件返回结果,而是会将这个事件挂在与执行栈不一样的队列中,咱们称之为任务队列(Task Queue)。
当主线程将执行栈中全部的代码执行完以后,主线程将会去查看任务队列是否有任务。若是有,那么主线程会依次执行那些任务队列中的回调函数。
不太理解的话,能够运行一下下面的代码,或者点击一下这个demo
结果是当a、b、c函数都执行完成以后,三个setTimeout才会依次执行。
let a = () => {
setTimeout(() => {
console.log('任务队列函数1')
}, 0)
for (let i = 0; i < 5000; i++) {
console.log('a的for循环')
}
console.log('a事件执行完')
}
let b = () => {
setTimeout(() => {
console.log('任务队列函数2')
}, 0)
for (let i = 0; i < 5000; i++) {
console.log('b的for循环')
}
console.log('b事件执行完')
}
let c = () => {
setTimeout(() => {
console.log('任务队列函数3')
}, 0)
for (let i = 0; i < 5000; i++) {
console.log('c的for循环')
}
console.log('c事件执行完')
}
a();
b();
c();
// 当a、b、c函数都执行完成以后,三个setTimeout才会依次执行
复制代码
异步任务分为 宏任务(macrotask) 与 微任务 (microtask),不一样的API注册的任务会依次进入自身对应的队列中,而后等待 Event Loop 将它们依次压入执行栈中执行。
宏任务(macrotask)::
script(总体代码)、setTimeout、setInterval、UI 渲染、 I/O、postMessage、 MessageChannel、setImmediate(Node.js 环境)
微任务(microtask):
Promise、 MutaionObserver、process.nextTick(Node.js环境)
Event Loop(事件循环)中,每一次循环称为 tick, 每一次tick的任务以下:
script
总体代码),若是有则执行宏任务 > 全部微任务 > 宏任务,以下图所示:
从上图咱们能够看出:
上面提到的demo结果能够这么理解:先执行script
宏任务,执行完了以后,再执行其余两个定时器宏任务。
下面这个题,不少人都应该看过/遇到过,从新来看会不会以为清晰不少:
// 执行顺序问题,考察频率挺高的,先本身想答案**
setTimeout(function () {
console.log(1);
});
new Promise(function(resolve,reject){
console.log(2)
resolve(3)
}).then(function(val){
console.log(val);
})
console.log(4);
复制代码
根据本文的解析,咱们能够获得:
先执行script
同步代码
先执行new Promise中的console.log(2),then后面的不执行属于微任务
而后执行console.log(4)
复制代码
执行完script
宏任务后,执行微任务,console.log(3),没有其余微任务了。
执行另外一个宏任务,定时器,console.log(1)。
根据本文的内容,能够很轻松,且有理有据的猜出写出正确答案:2,4,3,1.
相似上文的面试题还有不少,实则都大同小异,只要掌握了事件循环的机制,这些问题都会变得很简单。
文章若有不正确的地方欢迎各位路过的大佬鞭策!但愿你们看完能够有所收获,喜欢的话,赶忙点波订阅关注/喜欢。
我的blog and 掘金我的主页,如需转载,请放上原文连接并署名。码字不易,感谢支持!
若是喜欢本文的话,欢迎关注个人订阅号,漫漫技术路,期待将来共同窗习成长。
以上2018.6.16