事件循环
/**
* setTimeout函数,表示多少毫秒后,将传入函数放进异步队列中
*@param {function} 待放入异步队列函数
*@param {number} 等待时间
*@return timer编号
*/
console.log(1);
setTimeout(function () {
console.log(2);
}, 0);
console.log(3);
// logs 132
这是因为,js是单线程的,当主线程没有任务执行的时候,才会执行异步的任务console.log(2)
Javascript 单线程
JavasScript引擎是基于事件驱动和单线程执行的,JS引擎一直等待着任务队列中任务的到来,然后加以处理,浏览器无论什么时候都只有一个JS线程在运行程序,即主线程。
JS只能做同一件事情,即'阻塞式执行'
任务队列
异步操作必不可少,那js如何执行异步操作的呢?就是使用任务队列
任务队列:一个先进先出的队列,它里面存放着各种事件和任务
所有的任务分为同步任务与异步任务,我认为一般说到任务队列肯定是异步的。
同步任务
同步任务:在主线程上排队执行的任务,只有前一个任务执行完毕,才能执行后一个任务。
如输入: 变量的声明,赋值,同步函数:如果在函数返回的时候,调用者就能够拿到预期的返回值或者看到预期的效果,那么这个函数就是同步的。
异步任务
异步任务主要由以下组成
- setTimeout和setInterval
- DOM事件
- promise
- process.nextTick
- fs.readFile
- http.get
- 异步函数
任务队列又分为macro-task(宏任务)与micro-task(微任务)
宏任务
- io
- setTimeout
- setInterval
- setImmdiate
- requestAnimationFrame
微任务
- process.nextTick
- promise
- promise.then
- MutationObserver
宏任务与微任务的执行顺序:先执行一个宏任务,再把微任务全部执行,再去宏任务队列取下一个宏任务执行,再把微任务全部执行。
事件循环机制
事件循环js引擎会正常执行栈中内容,当遇到异步事件时,会将其放入任务队列中,继续执行栈中内容,等到当前执行栈中的所有任务执行完毕后,主线程处于空闲状态时,它会去查找任务队列是否有任务,如果有,则从队列中取出第一个任务,并将其同步代码块执行,当执行完毕后,又处于空闲,它又会去查找任务队列,这个过程叫做事件循环
举个例子,当某个按钮按下时触发onclick事件,它的事件处理程序代码就会被添加到任务队列中,并在线程空闲时执行。
那么回调callback是什么,回调是预测异步任务执行完毕后的要处理的同步代码块而已,它仅仅将函数跟异步任务放进了任务队列中。
主线程从任务队列中读取事件,这个过程是循环不断的,所以整个的这种运行机制又称为Event Loop。
为什么setTimeout写延时3s,但实际却是 5 6s之后执行。
这是因为异步队列的执行取决于主线程是拥挤还是空闲,如果主线程空闲,js就会从异步队列中获取任务,通过timer模块计算是否到时间了,到就执行代码块。