事件循环 事件循环Event Loop
1.关于java
java是单线程语言,最新的HTML5中提出了Web-Worker,但是Java的核心是单线程。所以所有java版本的“多线程”都是单线程模拟的,所有java多线程都是纸老虎!
2.java事件周期
事件循环是js实现异步的一种方法,也是js的执行机制。
首先,浏览器会逐个执行主任务队列中的所有同步任务,然后等待任务队列查看哪个任务可以执行。
然后把要执行的任务放到主任务队列中,当任务完成后,
等待任务看谁能执行,然后把这个任务放到主任务队列中执行...等等。
这种循环称为事件循环
Js是单线程,js任务要一个一个执行。如果一个任务花费的时间太长,那么下一个任务也必须等待。那么问题来了,如果我们想浏览新闻,但新闻中包含的超清晰图片加载缓慢,我们的网页是否应该一直卡到图片完全显示出来?因此,聪明的程序员将任务分为两类:1)同步任务2)异步任务
图表代表一个事件周期
#1.同步和异步任务分别进入不同的执行场所,同步进入主线程,异步进入Event Table并注册函数。
#2.当指定的事情完成后,事件表将把这个函数移到事件队列中。
#3.当主线程中的任务以空执行时,相应的函数将从事件队列中读取并在主线程中执行。
#4.上述过程会不断重复,这通常被称为事件循环。
主线程执行栈空是什么时候?
js引擎中有一个监控过程,会持续检查主线程执行栈是否为空。一旦是空,就会去事件队列检查是否有函数等待调用。~~~~
所以可以这样看:
1.浏览器线程首先执行同步任务,在途中遇到异步任务时,将其添加到等待任务队列中,然后继续向下执行。
2.所有同步任务执行完毕后,在任务队列中等待,逐个执行所有可执行的微任务。
3.执行完微任务后,先取第一个达到执行条件的宏任务执行,
4.执行结束后,等待任务队列清理并执行所有达到执行条件的微任务,
5.然后执行下一个宏任务。如果宏任务生成微任务或者宏任务生成宏任务,就会被添加到等待任务队列中,然后主线程会先执行所有的微任务,再逐个执行宏任务。
异步任务总是由先达到条件的人来执行,但也存在优先级问题,这取决于任务是宏任务还是微任务;微观任务的优先级高于宏观任务。
3.传动机构
在事件循环中,每个循环操作称为tick,每个tick的任务处理模型比较复杂,但关键步骤如下:
*执行宏任务
*如果在执行过程中遇到微任务,将其添加到微任务的任务队列中
*宏任务执行后,立即执行当前微任务队列中的所有微任务。
*当前宏任务完成后,开始检查渲染,然后GUI线程接管渲染
*渲染后,JS线程继续接管并启动下一个宏任务
一张图片解释道
宏任务:
任务,可以理解为执行栈每次执行的代码都是宏任务。
为了让JS内部任务和DOM任务能够有序执行,浏览器会在一个宏任务执行完之后,下一个宏任务执行之前,重新渲染页面。流程如下:
任务->渲染->任务->;...
微任务:
Microtask可以理解为在当前任务执行后立即执行的任务。也就是说,在当前任务之后、下一个任务之前和渲染之前。
因此,它的响应速度比setTimeout更快,因为不需要等待渲染。也就是说,宏任务执行后,其执行过程中产生的所有微任务都将被执行。
代码块1
setTimeout
});
新承诺{ 0
console . log;
决心;
}).然后
console.log
});
console . log;//2 4 3 1
分析:
settimeout是一个宏任务。虽然它是先执行的,但它被放入宏任务的eventqueue中。向下查看是否有微任务,发现Promise回调函数中的代码是同步输出2
然后,函数将他放入微任务序列。
主代码块输出4
主线流程中所有代码的执行完毕。首先,从微任务队列中取回函数,输出3个微任务全部完成
从宏任务的队列中获取函数。产出1
代码块2
console . log;
setTimeout;
process.nextTick;
})
新承诺{ 0
console . log;
决心;
}).然后
console.log
})
})
process.nextTick;
})
新承诺{ 0
console . log;
决心;
}).然后
console.log
})
setTimeout;
process.nextTick;
})
新承诺{ 0
console . log;
决心;
}).然后
console.log
})
})
1.主代码块输出1
2.宏任务1设置输出
3.微任务1流程
4 .立即执行promise,回调是同步输出7,然后是微任务2
5.宏任务2设置输出
主代码被完全执行
6.执行微任务1,输出6
7.执行微任务2,输出8
所有微任务均已执行
8.执行宏任务1,输出2,
增量任务流程
Promise立即执行回调输出4、微任务、
9.执行微任务输出3和输出5
10.执行宏任务2,输出9,
增量任务流程
Promise立即执行回调输出11、微任务,
11.执行微任务输出10、输出12
代码块3
异步功能async1{
console . log;
等待async2
console . log;
}
异步功能async2{
console . log;
}
console . log;
setTimeout;
}, 0)
async1
新承诺{ 0
console . log;
决心;
}).然后
console . log;
});
console . log;
1.输出“开始”
2 .设置输出宏任务
执行async1输出async1 start,执行async2,输出“async2”。
4.执行async2后,将wait async2后面的代码添加到微任务队列async 1 end’);
5.继续执行,新建Promise,同步输出“promise1”。然后,加入微任务队列,
6.输出端
7.执行当前宏任务后,检查微任务队列的输出async 1 end“promise 2”
8.执行完所有的微任务后,检查宏任务并输出setTimeout
更改上面的代码:
异步功能async1{
console . log;
letp =等待async2
console . log;
console . log;
}
异步功能async2{
console . log;
returnnew Promise= gt;{
决心;
}))
}
console . log;
setTimeout;
}, 0)
async1
新承诺{ 0
console . log;
决心;
}).然后
console . log;
});
console . log;
开始
async1开始
async2
承诺1
目标
承诺2
10
async1结束
定时器
new promise的操作就跟你 new 一个普通函数没区别,所以这一句其实是宏任务,但后面的then是微任务resolved后的promise对象会在这该级别事件队列结束之后才开始执行,及执行与该轮微任务队列中,始于下一级别宏任务之前resolved 的 Promise 是在本轮事件循环的末尾执行,总是晚于本轮循环的同步任务。如果出现两个这种微任务,则先出现的会先执行 async 函数中,遇到 await 会跳出当前函数,并让出线程,再将await后面的代码放到 微任务队列中SegmentFault认为社区应该与文章作者有更多的互动和交流。
-结束-