面试官老喜欢出这种题目问你,请说下这段代码的输出
,其中就会有坑,之所以说是坑是因为你不了解,懂了就是云淡风轻,不懂还是不懂,觉得遍地是坑,殊不知高手是可以飞的。
js是单线程语言,
js是一门单线程语言,哪怕es6,7都出来了,也没有改变它是单线程这一核心,只是出现了多了一些语法糖而已,所以一切的js版本的多线程都是用单线程模拟出来的,一切的js多线程都是纸老虎
js的执行机制是事件循环 Event Loop
js任务分为两类:同步任务,异步任务
当我们打开网站的时候,网页的渲染过程就是一大堆的同步任务,而像加载图片等耗时久的任务,就是异步任务。
上图的意思是:
- 同步任务和异步任务分别进入不同的执行场所,同步的进入主线程,异步的进入Event Table并注册函数
- 当指定的事情完成时,Event Table会将这个函数移入Event Queue
- 主线程内的任务执行完毕时,会去Event Queue读取相应的函数,进入主线程执行。
- 上述过程会不断的重复,也就是常说的Event Loop(事件循环)
直接上代码分析:
let data = [];
$.ajax({
url:www.javascript.com,
data:data,
success:() => {
console.log('发送成功!');
}
})
console.log('代码执行结束');
分析:
- ajax进入Event Table ,注册回调函数
success
- 执行
console.log('代码执行结束')
- ajax事件完成,回调函数success进入Event Queue
- 主线程从Event Queue读取函数success并执行
setTimeout(() => {
task();
},3000)
console.log('执行console');
分析:
- 执行setTimeou发现是异步任务,进入Event Table,3s后将回调函数加入到Event Queue中,
- 执行
console.log('执行console')
- 主线程执行结束,去Event Queue拿函数执行,发现没有,此过程不断的重复
- 3S 后Event Queue中有了回调函数,主线程拿之并执行
我们可以得知,setTimeout
这个函数,是经过指定时间后,把要执行的任务加入到Event Queue中,又因为单线程任务是一个个执行的,如果前面的任务需要执行的时间太久,那么只能等着,导致真正的延迟时间远大于3S
setTimeout(fn,0)
的含义是,指定某个任务在主线程最早得到空闲时执行,意思是不用等多少秒了,直接加入到Event Queue中。
setInterval
与setTimeout
含义差不多,setInterval
会每隔指定的时间将注册的函数置入Event Queue,
除了广义的同步任务和异步任务,对任务有跟精细的定义:
macro-task(宏任务): 包括整体代码script,setTimeout,setinterval
micro-task(微任务): Promise,process.nextTick
不同类型的任务会进入对应的Event Queue,比如setTimeout
和setInterval
会进入相同的Event Queue。
事件循环的顺序,决定js代码的执行顺序。进入整体代码(宏任务)后,开始第一次循环。接着执行所有的微任务。然后再次从宏任务开始,找到其中一个任务队列执行完毕(不是把任务全部执行完),再执行所有的微任务。
setTimeout(function() {
console.log('setTimeout');
})
new Promise(function(resolve) {
console.log('promise');
resolve() //不resolve()的话 then里面的回调是不会执行的
}).then(function() {
console.log('then');
})
console.log('console');
分析:
- 这段代码作为宏任务,进入主线程。
- 先遇到setTimeout,那么将其回调函数注册后分发到宏任务Event Queue。(注册过程与上同,下文不再描述)
- 接下来遇到了Promise,new Promise立即执行,then函数分发到微任务Event Queue。
- 遇到console.log(),立即执行。
- 好啦,整体代码script作为第一个宏任务执行结束,看看有哪些微任务?我们发现了then在微任务Event Queue里面,执行。
- ok,第一轮事件循环结束了,我们开始第二轮循环,当然要从宏任务Event Queue开始。我们发现了宏任务Event Queue中setTimeout对应的回调函数,立即执行。
- 结束。
console.log('1');
setTimeout(function() {
console.log('2');
process.nextTick(function() {
console.log('3');
})
new Promise(function(resolve) {
console.log('4');
resolve();
}).then(function() {
console.log('5')
})
})
process.nextTick(function() {
console.log('6');
})
new Promise(function(resolve) {
console.log('7');
resolve();
}).then(function() {
console.log('8')
})
setTimeout(function() {
console.log('9');
process.nextTick(function() {
console.log('10');
})
new Promise(function(resolve) {
console.log('11');
resolve();
}).then(function() {
console.log('12')
})
})
//1,7,6,8,2,4,3,5,9,11,10,12。
最后:
- javascript是一门单线程语言
- Event Loop是javascript的执行机制
本文章用于学习总结,参考自ssssyoki 这一次,彻底弄懂 JavaScript 执行机制
网友评论