js的执行机制
js是一门单线程语言js的执行机制就是事件循环(Event Loop)
·
js是一门单线程语言
js的执行机制就是事件循环(Event Loop)
1.JavaScript是单线程
JavaScript是一门单线程语言,也就是说同一时间只能做一件事。
2.为什么JavaScript是单线程
作为浏览器脚本语言,JavaScript主要用途是与用户互动以及操作DOM,所以它只能是单线程,否则会带来很严重的同步问题,如果JavaScript有两个线程,一个线程在DOM节点上添加内容,另一个线程删除这个节点,要以哪个线程为指令呢?
3.为什么js需要异步任务?
js是单线程,那么js任务也需要一个一个执行,如果一个任务消耗时间很长,那么后面的任务也需要等待。如果js不存在异步,只能自上而下执行,如果上一行解析时间很长,下面的代码就会堵塞,堵塞就意味着"卡死",用户体验会极差。
4.js存在同步任务和异步任务
同步任务:在主线程上排队执行任务,只有前一个任务执行完毕,才能执行后一个任务
异步任务:不进入主线程,而是进入"任务队列"的任务,只有"任务队列"通知主线程,某个异步任务可以执行了,该任务才会进入主线程执行。
除了广义的同步任务和异步任务,对任务更精细的定义:
macro-task(宏任务):包括整体代码script,setTimeout,setInterval
micro-task(微任务):Promise,process.nextTick
宏任务中有微任务,一定要将宏任务中的微任务执行完毕,再去执行下一个宏任务。
5.js事件循环是怎样运作的
- 同步任务和异步任务分别进入不同的“场所”,同步任务进入主线程,异步任务进入Event Table (事件表)并注册函数
- 指定的事件完成后,Event Table (事件表)会将这个函数移入到Event Queue (事件队列)
- 当主线程的任务完成后,会检查Event Queue (事件队列),如果有任务就全部执行,如果没有就进入下一个宏任务
- 这个过程会不断的重复,这就叫事件循环
6.例题
eg1:
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(){
console.log(11);
resolve();
}).then(function(){
console.log(12)
})
})
第一轮事件循环
一、整体script宏任务,从上到下执行。
- 遇到console.log(),输出1
- setTimeout1添加到宏任务队列中,待执行
- process.nextTick1添加到微任务队列中,待执行
- 遇到new Promise直接执行输出7,then加入到微任务队列,记微then1
- setTimeout2添加到宏任务队列中,待执行
二、执行微任务队列
- 执行prcess.nextTick1这个微任务,输出6
- 执行then1这个微任务,输出8
- 微任务队列清空,第一轮循环结束
第二轮事件循环
三、执行宏任务队列
- 执行setTimeout1这个宏任务
- 遇到console.log,输出2
- process.nextTick2添加到微任务队列
- 执行new Promise,输出4
- then添加到微任务队列,记为then2
四、执行微任务队列
- 执行process.nextTick2这个微任务,输出3
- 执行then2这个微任务,输出5
- 微任务队列清空,第二轮循环结束
第三轮事件循环
五、执行宏任务队列
- 执行setTimeout2这个宏任务
- 遇到console.log,输出9
- process.nextTick3添加到微任务队列
- 执行new Promise,输出11
- then添加到微任务队列,记为then3
六、执行微任务队列
- 执行process.nextTick3,输出10
- 执行then3这个微任务,输出12
- 微任务队列清空,第三轮循环结束
eg2:
console.log('1');
setTimeout(() => {
console.log('2');
},100)
setTimeout(() => {
console.log('3')
new Promise(resolve => {
console.log('4');
resolve();
}).then(() => {
console.log('5')
})
},100)
Promise.resolve().then(() => {
console.log('6');
})
new Promise(resolve => {
console.log('7');
resolve();
setTimeout(() => {
console.log('8')
},100)
}).then(() => {
console.log('9');
setTimeout(() => {
console.log('10')
},100)
})
console.log('11');
//1 7 11 6 9 2 3 4 5 8 10
一、首先,整体script宏任务
- 遇到console.log , 输出1
- setTimeout1添加到宏任务队列中,待执行
- setTimeout2添加到宏任务队列中,待执行
- then1添加到微任务队列中,待执行
- 执行new Promise输出7,将setTimeout3添加到宏任务队列中,将then2添加到微任务对列中
- 遇到console.log,输出11
二、执行微任务队列
- 执行then1,输出6
- 执行then2,输出9,将setTimeout4添加到宏任务队列
三、执行宏任务队列
- 执行setTimeout1这个宏任务,输出2
- 执行setTimeout2这个宏任务,输出3,执行new Promise输出4,将then3添加到微任务对列中
四、执行微任务队列
- 执行then3,输出5
五、执行宏任务队列
- 执行setTimeout3这个宏任务,输出8
- 执行setTimeout4这个宏任务,输出10
总之,执行的顺序就是,执行宏任务,再执行宏任务里面的微任务,如果执行微任务的过程中,产生了新的微任务,则继续执行微任务,等到微任务执行结束,再回到宏任务中进行下一轮循环
更多推荐
已为社区贡献2条内容
所有评论(0)