js的事件轮询机制
js事件轮询:
1、js 是一门单线程语言,从上往下执行的,首先,主线程读取js代码,此时是同步的环境
2、当主线程检测到异步操作,就会交给其他异步线程处理,然后继续执行主线程的的任务
3、异步任务执行完毕之后,判断异步任务的类型,异步任务可分成宏任务和微任务,像setTimeout、setInterval属于宏任务,promise.then属于微任务,不同的任务进入不同的队列,等待主线程空闲时候调用。
4、当主线程的的同步任务执行完毕之后,开始执行微任务队列里面的所有微任务,执行完微任务,就执行宏任务队列里面所有的宏任务
5、执行完成之后,主线程开始询问任务队列里面是否还有等待的任务,如果有则进入主线程继续执行
以上步骤重复执行就是事件轮询
js将异步队列里的任务划分为宏任务和微任务
宏任务有:1)setTimeout, setInterval, setImmediate,2)I/O、3)、UI rendering等
微任务有:1)process.nextTick、2)Promise、3)Object.observe(已废弃)、4)MutationObserver(html5新特性)等
举个例子
console.log('script start')
setTimeout(function(){
console.log('setTimeOut')
}, 0)
new Promise(function(resolve){
console.log('promise1')
resolve()
}).then(function(){
console.log('promise2')
})
console.log('script end')
流程如下:
1、打印script start,
2、遇到setTimeout放到宏任务队列里
3、打印promise1
4、将.then回调放入微任务队列里
5、打印script end
6、执行栈已清空,执行微任务队列打印promise2
7、微任务队列已清空,执行宏任务队列setTimeOut
8、所有任务队列清空
(如果还有任务的话则继续轮询 微任务 => 宏任务 => 微任务 => 宏任务…)
promise里的是同步代码,.then里的才是异步的
在实际开发中,经常会有轮询的效果。
1、js实现轮询效果==>使用setTimeout,clearTimeout方法
复制代码
function setTimer () {
let timer = null
axios.post(url, params).then(res=>{
if(res){//根据返回状态判断
timer = setTimeout(()=>{
this.setTimer ()
},2000)//2秒查一下
}else{
clearTimeout(timer);//清理定时任务
}
})
.catch((error)=> {
console.log(error);
});
}
复制代码
2.HTML5推出新的对象:websocket
js setInterval+setTimeout定时器轮询+终止轮询
常见的轮询方式:
window.timer = setInterval(()=>{
this.promiseFun()
},1000)
大家一般都会使用setInterval,但要注意单纯使用它可能导致页面卡死。
原因是setInterval不会清除定时器队列,每重复执行1次都会导致定时器叠加,卡死。但是setTimeout是自带清除定时器的所以可以叠加使用。
更好的轮询方式
window.timer = setInterval(() => {
setTimeout(this.promiseFun(), 0)
}, 1000)
结束轮询
在需要结束轮询的时候,如果是vue可以在beforeDestroy生命周期函数中销毁定时器
clearInterval(timer)